diff --git a/README.md b/README.md index 5304245..ba9e9e7 100644 --- a/README.md +++ b/README.md @@ -1,239 +1,120 @@

- logo du projet geocontext + logo du projet geocontext

# Geocontext -Serveur MCP expérimental fournissant du contexte spatial pour les LLM sur la base des [services de la Géoplateforme de l'IGN](https://cartes.gouv.fr/aide/fr/guides-utilisateur/utiliser-les-services-de-la-geoplateforme). +[![npm version](https://img.shields.io/npm/v/@ignfab/geocontext)](https://www.npmjs.com/package/@ignfab/geocontext) [![prototype](https://img.shields.io/badge/statut-prototype-orange)](https://github.com/ignfab/geocontext) -
-📋 Table des matières - -- [Geocontext](#geocontext) - - [Motivation](#motivation) - - [Mises en garde](#mises-en-garde) - - [Principes de conception](#principes-de-conception) - - [Utilisation](#utilisation) - - [Utilisation de la version publiée](#utilisation-de-la-version-publiée) - - [Autres exemples d'utilisation](#autres-exemples-dutilisation) - - [Développement](#développement) - - [Construction de la version locale](#construction-de-la-version-locale) - - [Utilisation de la version locale](#utilisation-de-la-version-locale) - - [Avec un client MCP compatible JSON](#avec-un-client-mcp-compatible-json) - - [Avec Docker en local](#avec-docker-en-local) - - [Debug de la version locale](#debug-de-la-version-locale) - - [Paramétrage](#paramétrage) - - [Tests](#tests) - - [Fonctionnalités (Tools)](#fonctionnalités-tools) - - [Utiliser des services spatiaux](#utiliser-des-services-spatiaux) - - [Recherche d'informations pour un lieu](#recherche-dinformations-pour-un-lieu) - - [Explorer les données vecteurs](#explorer-les-données-vecteurs) - - [Explorer les tables](#explorer-les-tables) - - [Explorer la structure des tables](#explorer-la-structure-des-tables) - - [Explorer les données des tables](#explorer-les-données-des-tables) - - [Voir également](#voir-également) - - [Contribution](#contribution) - - [Problèmes et demandes d'évolutions](#problèmes-et-demandes-dévolutions) - - [Proposer une nouvelle fonctionnalité](#proposer-une-nouvelle-fonctionnalité) - - [Crédits](#crédits) - - [Licence](#licence) - -
+**Geocontext** est un serveur MCP qui connecte vos LLM aux données géographiques françaises de référence publiées sur la [Géoplateforme de l'IGN](https://cartes.gouv.fr/aide/fr/guides-utilisateur/utiliser-les-services-de-la-geoplateforme). -## Motivation +## Exemples -Les LLM peuvent donner l'impression de disposer nativement de certaines capacités, mais ils dépendent, en pratique, des outils qui leur sont connectés. Par exemple, pour accéder à la date et à l'heure, un assistant doit être interfacé avec un serveur comme [MCP time](https://mcpservers.org/servers/modelcontextprotocol/time). De la même manière, pour lire une page web, il doit être relié à un outil tel que [MCP fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch#readme). +### Géocodage et altimétrie -S'il est techniquement possible de brancher des API REST/GeoJSON telle [APICARTO](https://github.com/IGNF/apicarto) à un LLM, la conception de ces dernières n'est pas adaptée (5000 résultats par défaut, grosse géométrie dans les réponses, géométries complexes à fournir,...). +
+ Quelle est l'altitude de la mairie de Vincennes ? -L'idée est ici d'**expérimenter la conception d'un MCP rendant les données et les services de la Géoplateforme accessibles par un LLM**. +

+ demo-geocontext - altitude mairie de Vincennes +

+
-## Mises en garde +### ADMINEXPRESS et CADASTRE -- Ce développement est un POC en incubation au sein d'[IGNfab](https://www.ign.fr/ignfab) sur la base d'un premier [prototype désormais archivé](https://github.com/mborne/geocontext) -- S'il s'avère utile de l'industrialiser, ce dépôt sera migré dans l'[organisation IGN principale](https://github.com/ignf) et l'outil sera renommé (ex : `IGNF/mcp-gpf-server`) -- Les [issues](https://github.com/ignfab/geocontext/issues) sont régulièrement mises à jour et traitées -- Une [roadmap](https://github.com/ignfab/geocontext/wiki) est également régulièrement alimentée -- 🪄 Cet outil ne relève pas de la magie : ses capacités sont définies et documentées dans [Fonctionnalités](#fonctionnalités). +
+ Quelles sont les informations administratives pour la tour Eiffel ? -## Principes de conception +

+ Claude - info administrative tour Eiffel +

+
-- **Ne pas répliquer les données de la Géoplateforme** (objectif : concentrer les efforts sur l'amélioration des services existants plutôt que sur leur duplication) -- **Prototyper les capacités manquantes pour l'usage des LLM avec la Géoplateforme** (objectif : combler les briques techniques nécessaires à une intégration robuste). Le projet s'appuie notamment sur [gpf-schema-store](https://github.com/ignfab/gpf-schema-store/) pour l'indexation et la description des schémas. -- **Maîtriser la volumétrie des réponses** (objectif : réduire le coût en jetons, limiter les hallucinations et permettre l'utilisation de modèles locaux). Cela se traduit en pratique par l'utilisation de références légères (`feature_ref`) aux objets géométriques dans les réponses et outils du MCP. +### BDTOPO -## Utilisation +
+ Combien y a-t-il de bâtiments de plus de 20 mètres à Vincennes ? -### Utilisation de la version publiée +

+ Mistral - bâtiment de plus de 20 mètres à Vincennes +

+
-Par exemple, avec "Cursor Settings / MCP / Add server" : +
+ Quelles sont les 5 communes les plus peuplées du Doubs ? -```json -{ - "mcpServers": { - "geocontext": { - "command": "npx", - "args": ["-y", "@ignfab/geocontext"] - } - } -} -``` +

+ demo-geocontext - 5 communes les plus peuplées du Doubs +

+
-### Autres exemples d'utilisation +### Géoportail de l'Urbanisme -- [Exemple d'utilisation avec Claude Desktop](docs/usage/claude-desktop.md) -- [Exemple d'utilisation avec MCPJam](docs/usage/mcpjam.md) +
+ Quel est le document PLU en vigueur pour le port de Marseille ? -## Développement +

+ Claude - PLU port de Marseille +

+
-Pré-requis : +
+ Quelles assiettes de SUP sont présentes autour de la mairie de Vincennes ? -- Node.js `24.5.0` ou supérieur recommandé (`22.21.0` minimum supporté) -- npm compatible avec la version de Node utilisée +

+ Claude - SUP mairie de Vincennes +

+
-Le dépôt fournit `.nvmrc` et `.node-version`. Si vous utilisez `nvm`, vous pouvez donc faire : -```bash -nvm install -nvm use -``` +## Points clés -### Construction de la version locale +- **Zéro duplication** — accès direct aux données de référence IGN, toujours à jour, sans téléchargement. +- **Optimisé pour les LLM** — réponses légères, filtrage côté serveur (par géométrie → par référence) pour réduire les tokens et les coûts. +- **Description enrichie des données** — réduit les hallucinations et facilite la découverte (implémentation anticipée de [OGC API Feature - schema](https://docs.ogc.org/is/23-058r2/23-058r2.html)). +- **LLM agnostique** — testé avec Claude, Mistral, Gemini et d'autres modèles. -```bash -git clone https://github.com/ignfab/geocontext -cd geocontext -npm ci -npm run build -``` +## Démarrage rapide -### Utilisation de la version locale +### ☁️ Version HTTP distante -#### Avec un client MCP compatible JSON +> en cours de déploiement — disponible prochainement. -```json -{ - "mcpServers": { - "geocontext": { - "command": "node", - "args":["--use-env-proxy", "/chemin/absolu/vers/geocontext/dist/index.js"] - } - } -} -``` - -L'option `--use-env-proxy` est facultative : elle active la prise en charge des variables d'environnement de proxy par Node.js. Ajoutez-la uniquement si votre environnement réseau en a besoin. Voir aussi la section [Configuration du proxy réseau](#configuration-du-proxy-reseau). +### Version locale -#### Avec Docker en local +> Pré-requis : Node.js (`>=24.5.0` à contrôler avec `node --version`) avec `npx`. -```bash -docker compose build -docker compose up -d -``` +Le MCP peut être démarré en tant que MCP local à l'aide de la commande `npx -y @ignfab/geocontext` qui démarrera la dernière version publiée (voir [@ignfab/geocontext](https://www.npmjs.com/package/@ignfab/geocontext)). -Ensuite : +La méthode varie en fonction des clients. Par exemple, avec "Cursor Settings / MCP / Add server" : ```json { "mcpServers": { "geocontext": { - "url": "http://localhost:3000/mcp" + "command": "npx", + "args": ["-y", "@ignfab/geocontext"] } } } ``` -### Debug de la version locale - -Cette commande lance **MCP Inspector**, l’outil de développement de MCP pour tester et déboguer un serveur local. - -```bash -npm run inspect:mcp -``` - -Pour les tests d'intégration et les tests E2E agent, voir [la documentation dédiée](docs/testing/README.md). - -## Paramétrage - -Pour une utilisation avancée : - -| Nom | Description | Valeur par défaut | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -| `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" | -| `HTTP_HOST` | Adresse d'écoute en mode HTTP. Utile avec Docker pour exposer le service via `0.0.0.0`. | "127.0.0.1" | -| `HTTP_PORT` | Port d'écoute du MCP | 3000 | -| `HTTP_MCP_ENDPOINT` | Chemin d'exposition du MCP en HTTP | "/mcp" | -| `HTTP_CORS_ALLOWED_ORIGINS` | Permet la [configuration de allowedOrigins pour protection contre les attaques par DNS rebinding](https://www.mcp-framework.com/docs/transports/http-stream#origin-validation-dns-rebinding-protection). Exemple : `HTTP_CORS_ALLOWED_ORIGINS="http://localhost:3000,https://geollm.beta.ign.fr"` | Aucun (warning) | -| `HTTP_TIMEOUT` | Délai maximal, en secondes, pour les appels HTTP sortants vers les services amont IGN. Au-delà, la requête est interrompue et l'outil renvoie une erreur de timeout structurée. | `15` | -| `GPF_WFS_RATE_LIMIT` | Nombre maximum de requêtes par seconde sur le WFS de la Géoplateforme | 30 | -| `GPF_WFS_MINISEARCH_OPTIONS` | Chaîne JSON optionnelle pour ajuster les options MiniSearch utilisées par `gpf_wfs_search_types` (`fields`, `combineWith`, `fuzzy`, `boost.namespace`, `boost.name`, `boost.title`, `boost.description`, `boost.properties`, `boost.enums`, `boost.identifierTokens`). | options par défaut de `@ignfab/gpf-schema-store` | -| `LOG_FORMAT` | Le format d'écriture des logs : "json" ou "simple". | "simple" | -| `LOG_LEVEL` | Le niveau d'écriture des logs : ["error", "info", ou "debug"](https://github.com/winstonjs/winston#logging-levels) | "debug" | - -Exemple : - -```bash -export GPF_WFS_MINISEARCH_OPTIONS='{"fields":["title","identifierTokens"],"combineWith":"OR","fuzzy":0.05,"boost":{"title":4,"name":5}}' -export HTTP_TIMEOUT=15 -``` - -Si `GPF_WFS_MINISEARCH_OPTIONS` est absent ou vide, les options par défaut restent celles de `@ignfab/gpf-schema-store`, y compris le comportement par défaut `OR` de MiniSearch pour `combineWith`. - - -
-Configuration du proxy réseau - -`geocontext` s'appuie sur la gestion native du proxy par Node.js. - -- En exécution locale, le serveur démarre avec `node --use-env-proxy` -- Les tests d'intégration propagent `NODE_USE_ENV_PROXY=1` au sous-processus MCP lancé en `stdio` -- Les tests E2E démarrent les workers Vitest avec `--use-env-proxy` - -Il suffit donc de définir les variables d'environnement standard selon votre contexte : - -```bash -export HTTP_PROXY=http://proxy.example:3128 -export HTTPS_PROXY=http://proxy.example:3128 -export NO_PROXY=localhost,127.0.0.1 -``` - -
- -### Tests - -Les commandes principales sont : - -```bash -npm run typecheck -npm run typecheck:test -npm test -npm run test:integration -npm run test:e2e -npm run test:coverage -npm run verify -npm run verify:full -``` - -`npm run verify:fast` inclut le type-check de l'application et des fichiers de test avant le build et les tests unitaires. - -Remarque : +### Autres exemples d'utilisation -- Les outils `gpf_wfs_search_types` et `gpf_wfs_describe_type` s'appuient sur un catalogue de schémas embarqué fourni par `@ignfab/gpf-schema-store`. -- Les outils `gpf_wfs_get_features` et `gpf_wfs_get_feature_by_id` interrogent toujours le service WFS de la Géoplateforme en direct. -- Le catalogue embarqué améliore la description des featureTypes mais il peut être légèrement décalé par rapport à l'état courant du WFS. +- [Exemple d'utilisation avec Claude Desktop](docs/usage/claude-desktop.md) +- [Exemple d'utilisation avec MCPJam](docs/usage/mcpjam.md) -## Fonctionnalités (Tools) +## Fonctionnalités -👉 Une description avancée des tools équivalente au niveau de détail de la méthode `tools/list` est disponible [ici](docs/mcp-tools.md). -On décrit ci-dessous succinctement les différents `tools` MCP proposés par `geocontext`. +Les fonctionnalités correspondent aux outils du MCP pour lesquels une description technique est disponible [ici](docs/mcp-tools.md). On se concentre ici sur le fonctionnel et les cas d'utilisation associés. ### Utiliser des services spatiaux -* [geocode(text)](src/tools/GeocodeTool.ts) s'appuie sur le [service d’autocomplétion de la Géoplateforme](https://geoservices.ign.fr/documentation/services/services-geoplateforme/autocompletion) pour **convertir un nom de lieu en position (lon,lat)**. +- [geocode(text)](docs/mcp-tools.md#geocode) s'appuie sur le [service d’autocomplétion de la Géoplateforme](https://geoservices.ign.fr/documentation/services/services-geoplateforme/autocompletion) pour **convertir un nom de lieu en position (lon,lat)**. > Ex : Quelle est la position (lon,lat) de la mairie de Vincennes? -* [altitude(lon,lat)](src/tools/AltitudeTool.ts) s'appuie sur le [service de calcul altimétrique de la Géoplateforme](https://geoservices.ign.fr/documentation/services/services-geoplateforme/altimetrie) pour **convertir une position en altitude**. +- [altitude(lon,lat)](docs/mcp-tools.md#altitude) s'appuie sur le [service de calcul altimétrique de la Géoplateforme](https://geoservices.ign.fr/documentation/services/services-geoplateforme/altimetrie) pour **convertir une position en altitude**. > Ex : Quelle est l'altitude de la mairie de Loray (25)? @@ -241,29 +122,27 @@ On décrit ci-dessous succinctement les différents `tools` MCP proposés par `g L'idée est ici de répondre à des questions précises en traitant côté serveur les appels aux [services WFS de la Géoplateforme](https://cartes.gouv.fr/aide/fr/guides-utilisateur/utiliser-les-services-de-la-geoplateforme/diffusion/wfs/) : -* [adminexpress(lon,lat)](src/tools/AdminexpressTool.ts) permet de **récupérer les informations administratives (commune, département, région,...)** pour un lieu donné par sa position. +- [adminexpress(lon,lat)](docs/mcp-tools.md#adminexpress) permet de **récupérer les informations administratives (commune, département, région,...)** pour un lieu donné par sa position. > Ex : Quelles sont les informations administratives pour la mairie de Vincennes? -* [cadastre(lon,lat)](src/tools/CadastreTool.ts) permet de **récupérer les informations cadastrales (parcelle, feuille,...)**. +- [cadastre(lon,lat)](docs/mcp-tools.md#cadastre) permet de **récupérer les informations cadastrales (parcelle, feuille,...)**. > Ex : Quelles sont les informations du cadastre pour la mairie de Vincennes? -* [urbanisme(lon,lat)](src/tools/UrbanismeTool.ts) permet de **récupérer les informations d'urbanisme (PLU,POS,CC,PSMV)** +- [urbanisme(lon,lat)](docs/mcp-tools.md#urbanisme) permet de **récupérer les informations d'urbanisme (PLU,POS,CC,PSMV)** > Ex : Quel est le document PLU en vigueur pour le port de Marseille? -* [assiette_sup(lon,lat)](src/tools/AssietteSupTool.ts) permet de **récupérer les Servitudes d'Utilité Publique (SUP)** +- [assiette_sup(lon,lat)](docs/mcp-tools.md#assiette_sup) permet de **récupérer les Servitudes d'Utilité Publique (SUP)** -> Ex: Quelles assiettes de SUP sont présentes autour de la mairie de Vincennes ? - -Les tools WFS orientés "objet" (`adminexpress`, `cadastre`, `urbanisme`, `assiette_sup`) exposent un `feature_ref { typename, feature_id }` quand l'objet source est réutilisable tel quel dans un appel ultérieur à `gpf_wfs_get_feature_by_id` ou `gpf_wfs_get_features` (ex : `spatial_operator="intersects_feature"`). +> Ex : Quelles assiettes de SUP sont présentes autour de la mairie de Vincennes ? ### Explorer les données vecteurs #### Explorer les tables -* [gpf_wfs_search_types(keywords,max_results=10)](src/tools/GpfWfsSearchTypesTool.ts) pour **rechercher un type WFS pertinent à partir de mots-clés et obtenir un `typename` valide**. La recherche est textuelle et configurable via `GPF_WFS_MINISEARCH_OPTIONS`. +- [gpf_wfs_search_types(keywords,max_results=10)](docs/mcp-tools.md#gpf_wfs_search_types) pour **rechercher un type WFS pertinent à partir de mots-clés**. > - Quels sont les millésimes ADMINEXPRESS disponibles sur la Géoplateforme? > - Quelle est la table de la BDTOPO correspondant aux bâtiments? @@ -271,78 +150,75 @@ Les tools WFS orientés "objet" (`adminexpress`, `cadastre`, `urbanisme`, `assie #### Explorer la structure des tables -* [gpf_wfs_describe_type(typename)](src/tools/GpfWfsDescribeTypeTool.ts) pour récupérer le **schéma détaillé d'un type WFS** depuis le catalogue embarqué (`id`, `namespace`, `name`, `title`, `description`, `properties`), en particulier avant d'appeler `gpf_wfs_get_features` +- [gpf_wfs_describe_type(typename)](docs/mcp-tools.md#gpf_wfs_describe_type) pour récupérer le **schéma détaillé d'un type WFS** depuis le catalogue embarqué (`id`, `namespace`, `name`, `title`, `description`, `properties`), en particulier avant d'appeler `gpf_wfs_get_features` > - Quelles sont les informations disponibles pour les communes avec ADMINEXPRESS-COG.LATEST? > - Compare le modèle des communes entre ADMINEXPRESS-COG:2024 et ADMINEXPRESS-COG.LATEST #### Explorer les données des tables -* [gpf_wfs_get_feature_by_id(typename,feature_id,...)](src/tools/GpfWfsGetFeatureByIdTool.ts) pour **récupérer exactement un objet WFS identifié par son `feature_id`**. +- [gpf_wfs_get_features(typename,...)](docs/mcp-tools.md#gpf_wfs_get_features) pour **récupérer les données d'une table** depuis le service WFS de la Géoplateforme. -Le tool accepte un contrat structuré : +> - Quelles sont les 5 communes les plus peuplées du Doubs (25)? +> - Combien y a-t-il de bâtiments à moins de 5 km de la tour Eiffel? -- `select` pour choisir les propriétés à renvoyer -- `result_type="request"` pour récupérer la requête compilée (`POST` + `get_url` éventuelle) pour utilisation par un autre tool (ex: affichage cartographique) -- `result_type="results"` pour renvoyer une `FeatureCollection` normalisée contenant exactement un seul objet +- [gpf_wfs_get_feature_by_id(typename,feature_id,...)](docs/mcp-tools.md#gpf_wfs_get_feature_by_id) pour **récupérer exactement un objet WFS identifié par son `feature_id`**. -Exemple : -- `typename="ADMINEXPRESS-COG.LATEST:commune", feature_id="commune.8952"` +## Mises en garde -* [gpf_wfs_get_features(typename,...)](src/tools/GpfWfsGetFeaturesTool.ts) pour **récupérer les données d'une table** depuis le service WFS de la Géoplateforme sans écrire de CQL à la main. +- 🧪 Ce projet est un **prototype en incubation** au sein d'[IGNfab](https://www.ign.fr/ignfab), basé sur un [prototype antérieur désormais archivé](https://github.com/mborne/geocontext). S'il s'avère pertinent de l'industrialiser, il sera migré vers l'[organisation IGN principale](https://github.com/ignf) (ex : `IGNF/mcp-gpf-server`). +- 🪄 Cet outil n'est pas magique : ses capacités sont strictement définies et documentées dans la section [Fonctionnalités](#fonctionnalités). -Le tool accepte un contrat structuré : +## Contribution -- `select` pour choisir les propriétés à renvoyer -- `where` pour filtrer les objets -- `order_by` pour trier les résultats -- `spatial_operator` et ses paramètres dédiés pour le spatial -- `result_type="request"` pour récupérer la requête compilée en `POST`, ainsi qu'une `get_url` dérivée quand elle reste raisonnablement portable en GET +### Signaler un problème -Exemples : +N'hésitez pas à [créer une issue](https://github.com/ignfab/geocontext/issues) si vous rencontrez un problème! -- `where=[{ property: "code_insee", operator: "eq", value: "25000" }]` -- `spatial_operator="bbox"` avec `bbox_west`, `bbox_south`, `bbox_east`, `bbox_north` -- `spatial_operator="dwithin_point"` avec `dwithin_lon`, `dwithin_lat`, `dwithin_distance_m` -- `spatial_operator="intersects_feature"` avec `intersects_feature_typename` et `intersects_feature_id` issus d'une `feature_ref` +**Merci de fournir** : -> - Quelles sont les 5 communes les plus peuplées du Doubs (25)? -> - Combien y a-t-il de bâtiments à moins de 5 km de la tour Eiffel? +- Le **client MCP** (ex : GitHub Copilot, Cursor, Claude Desktop) et le **mode de transport** (stdio ou http) utilisé. +- Le **modèle** utilisé (ex : Claude Sonnet 4.5) +- La **version de Geocontext** (visible sur [npmjs.com/@ignfab/geocontext](https://www.npmjs.com/package/@ignfab/geocontext) ou avec `npx @ignfab/geocontext --version`) +- La **demande** faite à l'assistant (**ex : "Combien y a-t-il de pont franchissant la Seine ?"**) +- Si possible, un export de la discussion au format Markdown. +### Demander une évolution -## Voir également +N'hésitez pas non plus à [créer une issue](https://github.com/ignfab/geocontext/issues) pour demander une évolution. -- https://github.com/datagouv/datagouv-mcp : MCP data.gouv.fr -- https://github.com/mapbox/mcp-server : MCP Mapbox -- https://git.tricoteuses.fr/logiciels/tricoteuses-api-parlement : MCP parlement français non officiel -- https://github.com/datagouv/datagouv-skill : Skills data.gouv.fr +Merci de **fournir la question type** pour laquelle vous souhaiteriez que le MCP aide à apporter une réponse. Par exemple : -## Contribution +- "Combien y a-t-il de bâtiments à moins de 5 km à pied de la tour Eiffel?" -> nous verrons comment exploiter les isochrones +- "Quelles sont les fonds de carte disponibles?" -> nous verrons comment exploiter le service WMTS de la Géoplateforme. -### Problèmes et demandes d'évolutions -N'hésitez pas à [créer une issue](https://github.com/ignfab/geocontext/issues) si vous rencontrez un problème! Merci de fournir : - -- L'assistant (ex: Github Copilot) et le modèle utilisé (ex: Claude Sonnet 4.5) -- La demande que vous faites à l'assistant (ex : "Combien y a-t-il de pont franchissant la Seine?") +## Paramétrage -### Proposer une nouvelle fonctionnalité +Voir [configuration du serveur MCP](docs/config.md) pour les configurations avancées (configuration d'un proxy d'entreprise, choix du mode de transport : stdio/http,...) -N'hésitez pas : +## Développement -- Forker le dépôt -- Créer un nouveau tool -- Tester de votre côté -- Faire une pull-request +Voir [Guide développeur](docs/dev.md) pour installation des dépendances, construction de l'application, exécution des tests,... ## Crédits -* [mcp-framework](https://mcp-framework.com) fournit le **cadre de développement du MCP** -* [@ignfab/gpf-schema-store](https://www.npmjs.com/package/@ignfab/gpf-schema-store) pour le **catalogue de schémas embarqué** utilisé par les outils d'exploration WFS. -* [MiniSearch](https://github.com/lucaong/minisearch) pour la **recherche par mot clé** utilisée dans `@ignfab/gpf-schema-store`. -* [jsts](https://bjornharrtell.github.io/jsts/) pour les **traitements géométriques** (ex : tri des réponses par distance au point recherché). -* [turfjs/distance](https://turfjs.org/docs/api/distance) pour les **calculs de distance** avec la [formule de Haversine](https://en.wikipedia.org/wiki/Haversine_formula). +- [mcp-framework](https://mcp-framework.com) : **cadre de développement du MCP** +- [@ignfab/gpf-schema-store](https://www.npmjs.com/package/@ignfab/gpf-schema-store) : **couche sémantique** / **catalogue de schémas embarqué** (en attendant [OGC API - Features - schema](https://docs.ogc.org/is/23-058r2/23-058r2.html)) + - [@camptocamp/ogc-client](https://camptocamp.github.io/ogc-client/#/) : **exploration WFS** (ex : parsing [GetCapabilities](https://data.geopf.fr/wfs?request=GetCapabilities&version=2.0.0&service=WFS)) + - [MiniSearch](https://github.com/lucaong/minisearch) : **recherche par mot clé** (`gpf_wfs_search_types`) +- [jsts](https://bjornharrtell.github.io/jsts/) : **traitements géométriques** (ex : tri des réponses par distance au point recherché). +- [turfjs/distance](https://turfjs.org/docs/api/distance) : **calculs de distance** avec la [formule de Haversine](https://en.wikipedia.org/wiki/Haversine_formula). + +## Voir également + +- https://github.com/datagouv/datagouv-mcp : MCP data.gouv.fr + +> Ex : Qui est le maire de la commune de Vincennes? + +- https://git.tricoteuses.fr/logiciels/tricoteuses-api-parlement : MCP parlement français non officiel +- https://github.com/datagouv/datagouv-skill : Skills data.gouv.fr ## Licence diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..e2f2900 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,26 @@ +# Configuration du serveur MCP + +## Points clés + +- L'utilisation du MCP sous forme d'un processus local (`npx -y @ignfab/geocontext`) ne requiert pas de paramétrage. +- **Cette section concerne les développeurs du MCP et les utilisateurs avancés du MCP** (démarrer localement la version HTTP, configurer les logs,...) + +## Principaux paramètres + +| Nom | Description | Valeur par défaut | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" (version locale) / "http" (docker) | +| `HTTP_HOST` | Adresse d'écoute en mode HTTP. Utile avec Docker pour exposer le service via `0.0.0.0`. | "127.0.0.1" | +| `HTTP_PORT` | Port d'écoute du MCP | 3000 | +| `HTTP_MCP_ENDPOINT` | Chemin d'exposition du MCP en HTTP | "/mcp" | +| `HTTP_CORS_ALLOWED_ORIGINS` | Permet la [configuration de allowedOrigins pour protection contre les attaques par DNS rebinding](https://www.mcp-framework.com/docs/transports/http-stream#origin-validation-dns-rebinding-protection). Exemple : `HTTP_CORS_ALLOWED_ORIGINS="http://localhost:3000,https://geollm.beta.ign.fr"` | Aucun (warning) | +| `HTTP_TIMEOUT` | Délai maximal, en secondes, pour les appels HTTP sortants vers les services amont IGN. Au-delà, la requête est interrompue et l'outil renvoie une erreur de timeout structurée. | `15` | +| `GPF_WFS_RATE_LIMIT` | Nombre maximum de requêtes par seconde sur le WFS de la Géoplateforme. | 30 | +| `GPF_WFS_MINISEARCH_OPTIONS` | Chaîne JSON optionnelle permettant de configurer `gpf_wfs_search_types`. | options par défaut de `@ignfab/gpf-schema-store` | +| `LOG_FORMAT` | Le format d'écriture des logs : "json" ou "simple". | "simple" | +| `LOG_LEVEL` | Le niveau d'écriture des logs : ["error", "info", ou "debug"](https://github.com/winstonjs/winston#logging-levels) | "debug" | + +## Paramétrages avancés + +- [Configuration d'un proxy d'entreprise](config/proxy.md) +- [Configurer le moteur de recherche](config/minisearch.md) diff --git a/docs/config/minisearch.md b/docs/config/minisearch.md new file mode 100644 index 0000000..d5d20fc --- /dev/null +++ b/docs/config/minisearch.md @@ -0,0 +1,19 @@ +# Configuration avancée de MiniSearch pour la recherche des types + +## Contexte + +La recherche des tables disponibles ( `gpf_wfs_search_types` ) s'appuie sur le moteur de recherche MiniSearch qui est intégré au dépôt [ignfab/gpf-schema-store](https://github.com/ignfab/gpf-schema-store#readme). + +**Cette documentation est à destination des développeurs** souhaitant tester des modifications sur les poids. + +## Configuration de la recherche + +Si `GPF_WFS_MINISEARCH_OPTIONS` est absent ou vide, les options par défaut `@ignfab/gpf-schema-store` sont utilisées (poids et le comportement par défaut `OR` de MiniSearch pour `combineWith`). + +Il est possible de configurer cette variable d'environnement comme suit pour modifier les comportements : + +```bash +export GPF_WFS_MINISEARCH_OPTIONS='{"fields":["title","identifierTokens"],"combineWith":"OR","fuzzy":0.05,"boost":{"title":4,"name":5}}' +export HTTP_TIMEOUT=15 +``` + diff --git a/docs/config/proxy.md b/docs/config/proxy.md new file mode 100644 index 0000000..d5c75f4 --- /dev/null +++ b/docs/config/proxy.md @@ -0,0 +1,23 @@ +# Configuration avancée du proxy réseau + +## Contexte + +Le projet `geocontext` s'appuie sur la gestion native du proxy par Node.js pour les appels HTTP sortants. + +**Cette documentation est à destination des développeurs et des utilisateurs de la version locale du MCP** travaillant derrière un proxy d'entreprise. + +## Configuration du proxy + +Le support du proxy est activé par l'environnement dans les principaux contextes d'exécution : + +- En exécution locale, le serveur démarre avec `node --use-env-proxy`. +- Les tests d'intégration propagent `NODE_USE_ENV_PROXY=1` au sous-processus MCP lancé en `stdio`. +- Les tests E2E démarrent les workers Vitest avec `--use-env-proxy`. + +Il suffit ensuite de définir les variables d'environnement standard selon votre contexte réseau : + +```bash +export HTTP_PROXY=http://proxy.example:3128 +export HTTPS_PROXY=http://proxy.example:3128 +export NO_PROXY=localhost,127.0.0.1 +``` diff --git a/docs/dev.md b/docs/dev.md new file mode 100644 index 0000000..b3811a3 --- /dev/null +++ b/docs/dev.md @@ -0,0 +1,206 @@ +# Guide développeur + +## Pré-requis + +- Node.js (voir `package.json` pour la version recommandée) +- npm compatible avec la version de Node utilisée + +Remarque : Le dépôt fournit `.nvmrc` et `.node-version`. Si vous utilisez `nvm`, vous pouvez donc faire : + +```bash +nvm install +nvm use +``` + + + + +## Installation + +```bash +# clonage du dépôt +git clone https://github.com/ignfab/geocontext +cd geocontext + +# téléchargement des dépendances +npm ci +``` + +## Construction + +!!!tip + La commande ci-après doit être relancé après chaque modification du code pour **reconstruction du `dist/`** + +```bash +npm run build +``` + +## Démarrer le serveur MCP + +La commande suivante démarre le serveur MCP en mode "stdio" : + +```bash +node --use-env-proxy dist/index.js +``` + +Avec certains clients MCP, vous serez amené à éditer un fichier JSON. Par exemple : + +```json +{ + "mcpServers": { + "geocontext": { + "command": "node", + "args": ["--use-env-proxy", "/chemin/absolu/vers/geocontext/dist/index.js"] + } + } +} +``` + +!!!tip + - L'option `--use-env-proxy` est facultative. Voir la [configuration du proxy réseau](./config/proxy.md). + - Voir [configuration du serveur MCP](./config.md) pour les paramètres disponibles + + +## Déboguer avec MCP Inspector + +**MCP Inspector** est l'outil de développement officiel pour tester et déboguer un serveur MCP local. + +```bash +npm run inspect:mcp # interface graphique +npm run inspect:mcp:cli # mode CLI +``` + +## Tests + +Le projet distingue trois niveaux de tests : + +- **Unitaires** : pas de réseau, exécutés par défaut. +- **Intégration niveau 1** (`test/integration/level1-protocol`) : appels MCP directs vers les tools, avec de vrais appels réseau vers la Géoplateforme. +- **E2E niveau 2** (`test/integration/level2-agent`) : un agent LangChain branché au serveur MCP local avec un vrai modèle LLM. + +Les niveaux 1 et 2 nécessitent un build à jour (`npm run build`) et un accès réseau aux services appelés. Les deux suites s'exécutent séquentiellement pour limiter la charge sur les services externes et éviter de démarrer plusieurs serveurs MCP en parallèle. + +### Vue d'ensemble des commandes + +| Commande | Rôle | +| --------------------------- | --------------------------------------------------------------- | +| `npm run typecheck` | Type-check de l'application (`tsconfig.json`) | +| `npm run typecheck:test` | Type-check des fichiers de test (`tsconfig.test.json`) | +| `npm test` / `test:unit` | Tests unitaires | +| `npm run test:integration` | Tests d'intégration niveau 1 | +| `npm run test:e2e` | Tests E2E agent niveau 2 | +| `npm run test:coverage` | Tests unitaires avec couverture | +| `npm run verify:fast` | `typecheck` + `typecheck:test` + `build` + `test:unit` | +| `npm run verify` | `verify:fast` + `test:integration` | +| `npm run verify:full` | `verify` + `test:e2e` | + +### Tests unitaires + +```bash +npm run test:unit +# ou simplement +npm test +``` + +### Tests d'intégration (niveau 1) + +```bash +npm run build +npm run test:integration +``` + +### Tests E2E agent (niveau 2) + +```bash +npm run build +npm run test:e2e +``` + +### Couverture + +```bash +npm run test:coverage +``` + +### Vérifications combinées + +```bash +npm run verify:fast # typecheck + build + tests unitaires +npm run verify # verify:fast + tests d'intégration niveau 1 +npm run verify:full # verify + tests E2E niveau 2 +``` + +### Variables d'environnement + +Communes aux suites d'intégration (niveaux 1 et 2) : + +| Variable | Description | +| ----------------------------------------- | ------------------------------------------------------------------- | +| `GEOCONTEXT_SERVER_PATH` | Chemin vers le point d'entrée du serveur (défaut : `dist/index.js`) | +| `GEOCONTEXT_LOG_LEVEL` | Niveau de log du serveur lancé par les tests | +| `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` | Configuration proxy réseau | + +Spécifiques aux tests E2E agent (`test:e2e`) : + +| Variable | Description | +| ------------------- | ------------------------------------------------------------------- | +| `MODEL_NAME` | Modèle LangChain à utiliser (défaut : `anthropic:claude-haiku-4-5`) | +| `ANTHROPIC_API_KEY` | Clé API Anthropic | +| `OPENAI_API_KEY` | Clé API OpenAI | +| `GOOGLE_API_KEY` | Clé API Google | +| `MISTRAL_API_KEY` | Clé API Mistral | + +La clé API requise dépend du provider indiqué dans `MODEL_NAME`. + +### Exemples de lancement des tests E2E + +Avec Anthropic : + +```bash +export MODEL_NAME=anthropic:claude-haiku-4-5 +export ANTHROPIC_API_KEY=... +npm run build +npm run test:e2e +``` + +Avec Ollama en local : + +```bash +export MODEL_NAME=ollama:llama3.1 +export OLLAMA_BASE_URL=http://127.0.0.1:11434 +npm run build +npm run test:e2e +``` + +## Dépannage + +- Si `test:integration` échoue immédiatement : vérifier que `dist/index.js` existe (`npm run build`). +- Si `test:e2e` est ignoré : vérifier que la clé API attendue par `MODEL_NAME` est définie. +- Si un provider local (Ollama, etc.) est utilisé derrière un proxy : ajouter `NO_PROXY=localhost,127.0.0.1`. + +## Commandes utiles + +### Mettre à jour des dépendances + +!!!warning + **zod doit rester en version 3** + +L'utilisation de [npm-check-updates](https://www.npmjs.com/package/npm-check-updates?activeTab=readme) est recommandée pour gérer les monter de version : + +```bash +# étudier les nouvelles versions disponible +npx -y npm-check-updates + +# mettre à jour les versions mineurs +npx -y npm-check-updates -t minor -u +``` + + +### Générer la documentation des tools MCP + +Pour mettre à jour `docs/mcp-tools.md` à partir des métadonnées des tools : + +```bash +npm run docs:mcp +``` + diff --git a/docs/imgs/batiment-20m-vincennes.png b/docs/imgs/batiment-20m-vincennes.png new file mode 100644 index 0000000..b69cd4b Binary files /dev/null and b/docs/imgs/batiment-20m-vincennes.png differ diff --git a/docs/imgs/usage/claude-administratif-tour-eiffel.png b/docs/imgs/usage/claude-administratif-tour-eiffel.png new file mode 100644 index 0000000..95ec135 Binary files /dev/null and b/docs/imgs/usage/claude-administratif-tour-eiffel.png differ diff --git a/docs/imgs/usage/claude-altitude-mairie-vincennes.png b/docs/imgs/usage/claude-altitude-mairie-vincennes.png new file mode 100644 index 0000000..b93c72a Binary files /dev/null and b/docs/imgs/usage/claude-altitude-mairie-vincennes.png differ diff --git a/docs/imgs/usage/claude-plu-marseille.png b/docs/imgs/usage/claude-plu-marseille.png new file mode 100644 index 0000000..97435f0 Binary files /dev/null and b/docs/imgs/usage/claude-plu-marseille.png differ diff --git a/docs/imgs/usage/claude-sup-mairie-vincennes.png b/docs/imgs/usage/claude-sup-mairie-vincennes.png new file mode 100644 index 0000000..6306479 Binary files /dev/null and b/docs/imgs/usage/claude-sup-mairie-vincennes.png differ diff --git a/docs/imgs/usage/demo-5-communes-doubs.png b/docs/imgs/usage/demo-5-communes-doubs.png new file mode 100644 index 0000000..59bc138 Binary files /dev/null and b/docs/imgs/usage/demo-5-communes-doubs.png differ diff --git a/docs/imgs/usage/demo-altitude-mairie-vincennes.png b/docs/imgs/usage/demo-altitude-mairie-vincennes.png new file mode 100644 index 0000000..19adcff Binary files /dev/null and b/docs/imgs/usage/demo-altitude-mairie-vincennes.png differ diff --git a/docs/imgs/usage/mistral-batiment-20m-vincennes.png b/docs/imgs/usage/mistral-batiment-20m-vincennes.png new file mode 100644 index 0000000..742a238 Binary files /dev/null and b/docs/imgs/usage/mistral-batiment-20m-vincennes.png differ diff --git a/docs/imgs/vscode-command-stdio.png b/docs/imgs/vscode-command-stdio.png new file mode 100644 index 0000000..e72b7c1 Binary files /dev/null and b/docs/imgs/vscode-command-stdio.png differ diff --git a/docs/testing/README.md b/docs/testing/README.md deleted file mode 100644 index e62dc71..0000000 --- a/docs/testing/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# Tests d'intégration - -Le dépôt contient deux niveaux de tests d'intégration : - -- `test/integration/level1-protocol` teste directement les tools MCP avec de vrais appels réseau vers la Géoplateforme -- `test/integration/level2-agent` teste un agent LangChain branché au serveur MCP local, avec un vrai modèle LLM - -## Pré requis - -- installer les dépendances avec `npm install` -- construire le serveur local avec `npm run build` -- disposer d'un accès réseau vers les services appelés - -## Lancer les tests - -Tests d'intégration de niveau 1 : - -```bash -npm run test:integration -``` - -Tests E2E agent de niveau 2 : - -```bash -npm run test:e2e -``` - -Les deux suites s'exécutent séquentiellement pour limiter la charge sur les services externes et éviter de démarrer plusieurs serveurs MCP en parallèle. - -## Variables d'environnement utiles - -Communes aux suites d'intégration : - -- `GEOCONTEXT_SERVER_PATH` pour cibler un autre point d'entrée que `dist/index.js` -- `GEOCONTEXT_LOG_LEVEL` pour ajuster les logs du serveur lancé par les tests -- `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` si l'environnement passe par un proxy - -Spécifiques aux tests agent (`test:e2e`) : - -- `MODEL_NAME` pour choisir le modèle LangChain, par défaut `anthropic:claude-haiku-4-5` -- la clé API attendue dépend du provider choisi dans `MODEL_NAME` -- exemples : `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`, `MISTRAL_API_KEY` - -## Exemples - -Niveau 1 : - -```bash -npm run build -npm run test:integration -``` - -Niveau 2 avec Anthropic : - -```bash -export MODEL_NAME=anthropic:claude-haiku-4-5 -export ANTHROPIC_API_KEY=... -npm run build -npm run test:e2e -``` - -Niveau 2 avec Ollama local : - -```bash -export MODEL_NAME=ollama:llama3.1 -export OLLAMA_BASE_URL=http://127.0.0.1:11434 -npm run build -npm run test:e2e -``` - -## Dépannage rapide - -- si `test:integration` échoue immédiatement, vérifier que `dist/index.js` existe bien après `npm run build` -- si `test:e2e` est ignoré, vérifier que la clé API attendue par `MODEL_NAME` est présente -- si un provider local est utilisé derrière un proxy, renseigner aussi `NO_PROXY=localhost,127.0.0.1`