@ignfab/geocontext 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +349 -259
  2. package/dist/gpf/adminexpress.d.ts +17 -8
  3. package/dist/gpf/adminexpress.js +40 -17
  4. package/dist/gpf/adminexpress.js.map +1 -1
  5. package/dist/gpf/altitude.d.ts +21 -9
  6. package/dist/gpf/altitude.js +5 -5
  7. package/dist/gpf/altitude.js.map +1 -1
  8. package/dist/gpf/geocode.d.ts +25 -4
  9. package/dist/gpf/geocode.js +5 -5
  10. package/dist/gpf/geocode.js.map +1 -1
  11. package/dist/gpf/parcellaire-express.d.ts +19 -9
  12. package/dist/gpf/parcellaire-express.js +59 -26
  13. package/dist/gpf/parcellaire-express.js.map +1 -1
  14. package/dist/gpf/urbanisme.d.ts +24 -16
  15. package/dist/gpf/urbanisme.js +81 -33
  16. package/dist/gpf/urbanisme.js.map +1 -1
  17. package/dist/gpf/{wfs.js → wfs-schema-catalog.js} +1 -1
  18. package/dist/gpf/wfs-schema-catalog.js.map +1 -0
  19. package/dist/helpers/RateLimiter.d.ts +44 -0
  20. package/dist/helpers/RateLimiter.js +52 -0
  21. package/dist/helpers/RateLimiter.js.map +1 -0
  22. package/dist/helpers/distance.d.ts +2 -1
  23. package/dist/helpers/distance.js +2 -1
  24. package/dist/helpers/distance.js.map +1 -1
  25. package/dist/helpers/errors/toolError.d.ts +30 -0
  26. package/dist/helpers/errors/toolError.js +193 -0
  27. package/dist/helpers/errors/toolError.js.map +1 -0
  28. package/dist/helpers/errors/zodErrorMapFr.d.ts +20 -0
  29. package/dist/helpers/errors/zodErrorMapFr.js +191 -0
  30. package/dist/helpers/errors/zodErrorMapFr.js.map +1 -0
  31. package/dist/helpers/http.d.ts +67 -7
  32. package/dist/helpers/http.js +458 -84
  33. package/dist/helpers/http.js.map +1 -1
  34. package/dist/helpers/jsonSchema.d.ts +20 -2
  35. package/dist/helpers/jsonSchema.js +12 -0
  36. package/dist/helpers/jsonSchema.js.map +1 -1
  37. package/dist/helpers/schemas.d.ts +4 -4
  38. package/dist/helpers/wfs_engine/attributeFilter.d.ts +51 -0
  39. package/dist/helpers/wfs_engine/attributeFilter.js +258 -0
  40. package/dist/helpers/wfs_engine/attributeFilter.js.map +1 -0
  41. package/dist/helpers/wfs_engine/byId.d.ts +76 -0
  42. package/dist/helpers/wfs_engine/byId.js +106 -0
  43. package/dist/helpers/wfs_engine/byId.js.map +1 -0
  44. package/dist/helpers/wfs_engine/execution.d.ts +72 -0
  45. package/dist/helpers/wfs_engine/execution.js +95 -0
  46. package/dist/helpers/wfs_engine/execution.js.map +1 -0
  47. package/dist/helpers/wfs_engine/features.d.ts +64 -0
  48. package/dist/helpers/wfs_engine/features.js +138 -0
  49. package/dist/helpers/wfs_engine/features.js.map +1 -0
  50. package/dist/helpers/wfs_engine/geometry.d.ts +16 -0
  51. package/dist/helpers/wfs_engine/geometry.js +44 -0
  52. package/dist/helpers/wfs_engine/geometry.js.map +1 -0
  53. package/dist/helpers/wfs_engine/properties.d.ts +51 -0
  54. package/dist/helpers/wfs_engine/properties.js +128 -0
  55. package/dist/helpers/wfs_engine/properties.js.map +1 -0
  56. package/dist/helpers/wfs_engine/queryPreparation.d.ts +32 -0
  57. package/dist/helpers/wfs_engine/queryPreparation.js +149 -0
  58. package/dist/helpers/wfs_engine/queryPreparation.js.map +1 -0
  59. package/dist/helpers/wfs_engine/request.d.ts +94 -0
  60. package/dist/helpers/wfs_engine/request.js +197 -0
  61. package/dist/helpers/wfs_engine/request.js.map +1 -0
  62. package/dist/helpers/wfs_engine/response.d.ts +80 -0
  63. package/dist/helpers/wfs_engine/response.js +135 -0
  64. package/dist/helpers/wfs_engine/response.js.map +1 -0
  65. package/dist/helpers/wfs_engine/schema.d.ts +209 -0
  66. package/dist/helpers/{wfs_internal → wfs_engine}/schema.js +50 -10
  67. package/dist/helpers/wfs_engine/schema.js.map +1 -0
  68. package/dist/helpers/wfs_engine/spatialCql.d.ts +46 -0
  69. package/dist/helpers/wfs_engine/spatialCql.js +54 -0
  70. package/dist/helpers/wfs_engine/spatialCql.js.map +1 -0
  71. package/dist/helpers/wfs_engine/spatialFilter.d.ts +14 -0
  72. package/dist/helpers/wfs_engine/spatialFilter.js +131 -0
  73. package/dist/helpers/wfs_engine/spatialFilter.js.map +1 -0
  74. package/dist/index.js +65 -23
  75. package/dist/index.js.map +1 -1
  76. package/dist/logger.d.ts +1 -1
  77. package/dist/logger.js +4 -1
  78. package/dist/logger.js.map +1 -1
  79. package/dist/tools/AdminexpressTool.d.ts +42 -33
  80. package/dist/tools/AdminexpressTool.js +19 -3
  81. package/dist/tools/AdminexpressTool.js.map +1 -1
  82. package/dist/tools/AltitudeTool.d.ts +35 -44
  83. package/dist/tools/AltitudeTool.js +19 -8
  84. package/dist/tools/AltitudeTool.js.map +1 -1
  85. package/dist/tools/AssietteSupTool.d.ts +51 -34
  86. package/dist/tools/AssietteSupTool.js +18 -2
  87. package/dist/tools/AssietteSupTool.js.map +1 -1
  88. package/dist/tools/BaseTool.d.ts +17 -0
  89. package/dist/tools/BaseTool.js +41 -0
  90. package/dist/tools/BaseTool.js.map +1 -0
  91. package/dist/tools/CadastreTool.d.ts +53 -33
  92. package/dist/tools/CadastreTool.js +18 -2
  93. package/dist/tools/CadastreTool.js.map +1 -1
  94. package/dist/tools/GeocodeTool.d.ts +53 -37
  95. package/dist/tools/GeocodeTool.js +17 -2
  96. package/dist/tools/GeocodeTool.js.map +1 -1
  97. package/dist/tools/GpfWfsDescribeTypeTool.d.ts +66 -94
  98. package/dist/tools/GpfWfsDescribeTypeTool.js +26 -15
  99. package/dist/tools/GpfWfsDescribeTypeTool.js.map +1 -1
  100. package/dist/tools/GpfWfsGetFeatureByIdTool.d.ts +89 -0
  101. package/dist/tools/GpfWfsGetFeatureByIdTool.js +99 -0
  102. package/dist/tools/GpfWfsGetFeatureByIdTool.js.map +1 -0
  103. package/dist/tools/GpfWfsGetFeaturesTool.d.ts +89 -123
  104. package/dist/tools/GpfWfsGetFeaturesTool.js +31 -144
  105. package/dist/tools/GpfWfsGetFeaturesTool.js.map +1 -1
  106. package/dist/tools/GpfWfsSearchTypesTool.d.ts +41 -32
  107. package/dist/tools/GpfWfsSearchTypesTool.js +18 -3
  108. package/dist/tools/GpfWfsSearchTypesTool.js.map +1 -1
  109. package/dist/tools/UrbanismeTool.d.ts +42 -33
  110. package/dist/tools/UrbanismeTool.js +18 -2
  111. package/dist/tools/UrbanismeTool.js.map +1 -1
  112. package/package.json +51 -24
  113. package/dist/gpf/wfs.js.map +0 -1
  114. package/dist/helpers/wfs.d.ts +0 -27
  115. package/dist/helpers/wfs.js +0 -55
  116. package/dist/helpers/wfs.js.map +0 -1
  117. package/dist/helpers/wfs_internal/compile.d.ts +0 -46
  118. package/dist/helpers/wfs_internal/compile.js +0 -595
  119. package/dist/helpers/wfs_internal/compile.js.map +0 -1
  120. package/dist/helpers/wfs_internal/request.d.ts +0 -38
  121. package/dist/helpers/wfs_internal/request.js +0 -92
  122. package/dist/helpers/wfs_internal/request.js.map +0 -1
  123. package/dist/helpers/wfs_internal/response.d.ts +0 -21
  124. package/dist/helpers/wfs_internal/response.js +0 -29
  125. package/dist/helpers/wfs_internal/response.js.map +0 -1
  126. package/dist/helpers/wfs_internal/schema.d.ts +0 -167
  127. package/dist/helpers/wfs_internal/schema.js.map +0 -1
  128. /package/dist/gpf/{wfs.d.ts → wfs-schema-catalog.d.ts} +0 -0
package/README.md CHANGED
@@ -1,259 +1,349 @@
1
- # geocontext
2
-
3
- Un serveur MCP expérimental fournissant du contexte spatial pour les LLM.
4
-
5
- ## Motivation
6
-
7
- Les LLM renforcent l'idée que la magie est possible avec l'informatique. Il n'en est rien. Pour qu'un assistant soit en mesure de connaître la date et l'heure, il faut par exemple l'interfacer avec un [MCP time](https://mcpservers.org/servers/modelcontextprotocol/time). De même, pour qu'il soit en mesure de lire une page, il faut par exemple l'interfacer un [MCP fetch](https://github.com/modelcontextprotocol/servers/tree/main/src/fetch#readme).
8
-
9
- En matière de données géographique, si un utilisateur pose une question impliquant que l'assistant soit en mesure de [connaître la position d'une adresse, il y a de bonne chance que la réponse soit plausible mais fausse](https://github.com/mborne/llm-experimentations/tree/main/chatgpt-geocodage-limites#readme).
10
-
11
- S'il est techniquement possible de brancher des API REST/GeoJSON telle APICARTO, la conception de ces dernières n'est pas adaptée (5000 résultat par défaut, grosse géométrie dans les réponses, géométries complexes à fournir,...).
12
-
13
- 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**.
14
-
15
- ## Mises en garde
16
-
17
- - Ce développement est un POC en incubation au sein d'ignfab (archivage en cours de [mborne/geocontext](https://github.com/mborne/geocontext))
18
- - S'il s'avère utile de l'industrialiser, le dépôt sera migré sous responsabilité IGN et l'outil sera renommé (ex : `IGNF/mcp-gpf-server`)
19
- - Plusieurs problèmes et améliorations possibles ont été identifiés et sont en cours de mitigation/résolution (c.f. [issues](https://github.com/ignfab/geocontext/issues?q=is%3Aissue%20state%3Aopen%20label%3Ametadata)).
20
- - Cet outil n'est pas magique (voir [Fonctionnalités](#fonctionnalités) pour avoir une idée de ses capacités)
21
-
22
- ## Principes de conception
23
-
24
- - **Ne pas copier les données de la Géoplateforme** (but : identifier les améliorations possibles sur le services plutôt que les doublonner)
25
- - **Limiter au maximum la taille des réponses** (but : optimiser le nombre de jeton / éviter les hallucinations / pouvoir utiliser des modèles locaux)
26
- - ...
27
-
28
- ## Utilisation
29
-
30
- ### Utilisation de la version publiée
31
-
32
- Par exemple, avec "Cursor Settings / MCP / Add server" :
33
-
34
- ```json
35
- {
36
- "mcpServers": {
37
- "geocontext": {
38
- "command": "npx",
39
- "args": ["-y", "@ignfab/geocontext"]
40
- }
41
- }
42
- }
43
- ```
44
-
45
- ### Utilisation avec Docker
46
-
47
- ```bash
48
- docker compose build
49
- docker compose up -d
50
- ```
51
-
52
- Remarque :
53
-
54
- - le `docker-compose.yaml` fournit `HTTP_HOST=0.0.0.0` pour rendre le serveur HTTP joignable depuis l'hôte ;
55
- - sans ce paramètre, `mcp-framework` écoute par défaut sur `127.0.0.1` en mode HTTP, ce qui n'est pas adapté à une exécution en conteneur.
56
-
57
- Ensuite :
58
-
59
- ```json
60
- {
61
- "mcpServers": {
62
- "geocontext": {
63
- "url": "http://localhost:3000/mcp"
64
- }
65
- }
66
- }
67
- ```
68
-
69
- ## Développement
70
-
71
- ### Construction de la version locale
72
-
73
- ```bash
74
- git clone https://github.com/ignfab/geocontext
75
- cd geocontext
76
- npm install
77
- npm run build
78
- ```
79
-
80
- ### Utilisation de la version locale
81
-
82
- #### Avec un client MCP compatible JSON
83
-
84
- ```json
85
- {
86
- "mcpServers": {
87
- "geocontext": {
88
- "command": "node",
89
- "args":["/chemin/absolu/vers/geocontext/dist/index.js"]
90
- }
91
- }
92
- }
93
- ```
94
-
95
- #### Avec Codex CLI / VS Code
96
-
97
- Avec Codex CLI ou l'extension Codex pour VS Code, la configuration se fait dans `~/.codex/config.toml` :
98
-
99
- ```toml
100
- [mcp_servers.geocontext]
101
- command = "node"
102
- args = ["/chemin/absolu/vers/geocontext/dist/index.js"]
103
-
104
- # Définition d'un corporate proxy si nécessaire
105
- [mcp_servers.geocontext.env]
106
- HTTPS_PROXY = "http://proxy.domain.fr:3128"
107
- HTTP_PROXY = "http://proxy.domain.fr:3128"
108
- NO_PROXY = "localhost,127.0.0.1"
109
- http_proxy = "http://proxy.domain.fr:3128"
110
- https_proxy = "http://proxy.domain.fr:3128"
111
- no_proxy = "localhost,127.0.0.1"
112
- ```
113
-
114
- Après mise à jour de `~/.codex/config.toml`, relancer la session Codex CLI ou recharger VS Code si l'extension Codex est déjà ouverte.
115
-
116
- ### Debug de la version locale
117
-
118
- ```bash
119
- npx -y @modelcontextprotocol/inspector node dist/index.js
120
- ```
121
-
122
- ## Paramétrage
123
-
124
- Pour une utilisation avancée :
125
-
126
- | Nom | Description | Valeur par défaut |
127
- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
128
- | `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" |
129
- | `HTTP_HOST` | Adresse d'écoute en mode HTTP. Utile avec Docker pour exposer le service via `0.0.0.0`. | défaut `mcp-framework` (`127.0.0.1`) |
130
- | `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` |
131
- | `LOG_FORMAT` | Le format d'écriture des logs : "json" ou "simple". | "simple" |
132
- | `LOG_LEVEL` | Le niveau d'écriture des logs : ["error", "info", ou "debug"](https://github.com/winstonjs/winston#logging-levels) | "debug" |
133
-
134
- Exemple :
135
-
136
- ```bash
137
- export GPF_WFS_MINISEARCH_OPTIONS='{"fields":["title","identifierTokens"],"combineWith":"OR","fuzzy":0.05,"boost":{"title":4,"name":5}}'
138
- ```
139
-
140
- 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`.
141
-
142
- Remarque :
143
-
144
- - 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`.
145
- - L'outil `gpf_wfs_get_features` interroge toujours le service WFS de la Géoplateforme en direct.
146
- - 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.
147
-
148
- ## Fonctionnalités
149
-
150
- ### Utiliser des services spatiaux
151
-
152
- Quelques services de la Géoplateforme :
153
-
154
- * [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)**.
155
-
156
- > Ex : Quelle est la position (lon,lat) de la mairie de Vincennes?
157
-
158
- * [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**.
159
-
160
- > Ex : Quelle est l'altitude de la mairie de Loray (25)?
161
-
162
- ### Recherche d'informations pour un lieu
163
-
164
- L'idée est ici de répondre à des précises en traitant côté serveur les appels aux services WFS de la Géoplateforme :
165
-
166
- * [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.
167
-
168
- > Ex : Quelles sont les informations administrative pour la mairie de Vincennes?
169
-
170
- * [cadastre(lon,lat)](src/tools/CadastreTool.ts) permet de **récupérer les informations cadastrales (parcelle, feuille,...)**.
171
-
172
- > Ex : Quelles sont les informations du cadastre pour la mairie de Vincennes?
173
-
174
- * [urbanisme(lon,lat)](src/tools/UrbanismeTool.ts) permet de **récupérer les informations d'urbanisme (PLU,POS,CC,PSMV)**
175
-
176
- > Ex : Quel est le document PLU en vigueur pour le port de Marseille?
177
-
178
- * [assiette_sup(lon,lat)](src/tools/AssietteSupTool.ts) permet de **récupérer les Servitude d'Utilité Publiques (SUP)**
179
-
180
- 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_features`, notamment avec `spatial_operator="intersects_feature"`.
181
-
182
- ### Explorer les données vecteurs
183
-
184
- #### Explorer les tables
185
-
186
- * [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`.
187
-
188
- > - Quels sont les millésimes ADMINEXPRESS disponibles sur la Géoplateforme?
189
- > - Quelle est la table de la BDTOPO correspondant aux bâtiments?
190
- > - Dans quelle table de la BDTOPO peut-on trouver les ponts?
191
-
192
- #### Explorer la structure des tables
193
-
194
- * [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`
195
-
196
- > - Quelles sont les informations disponibles pour les communes avec ADMINEXPRESS-COG.LATEST?
197
- > - Compare le modèle des communes entre ADMINEXPRESS-COG:2024 et ADMINEXPRESS-COG.LATEST
198
-
199
- #### Explorer les données des tables
200
-
201
- * [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.
202
-
203
- Le tool accepte un contrat structuré :
204
-
205
- - `select` pour choisir les propriétés à renvoyer
206
- - `where` pour filtrer les objets
207
- - `order_by` pour trier les résultats
208
- - `spatial_operator` et ses paramètres dédiés pour le spatial en `lon/lat`
209
- - `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
210
-
211
- Exemples :
212
-
213
- - `where=[{ property: "code_insee", operator: "eq", value: "25000" }]`
214
- - `spatial_operator="bbox"` avec `bbox_west`, `bbox_south`, `bbox_east`, `bbox_north`
215
- - `spatial_operator="dwithin_point"` avec `dwithin_lon`, `dwithin_lat`, `dwithin_distance_m`
216
- - `spatial_operator="intersects_feature"` avec `intersects_feature_typename` et `intersects_feature_id` issus d'une `feature_ref`
217
-
218
- > - Quelles sont les 5 communes les plus peuplées du Doubs (25)?
219
- > - Combien y-a-t'il de bâtiments à moins de 5 km de la tour Eiffel?
220
-
221
- ## Contribution
222
-
223
- ### Problèmes et demandes d'évolutions
224
-
225
- N'hésitez pas à [créer une issue](https://github.com/ignfab/geocontext/issues) si vous rencontrez un problème! Merci de fournir :
226
-
227
- - L'assistant et le modèle utilisé
228
- - La demande que vous faite à l'assistant (ex : "Combien y a-t'il de pont franchissant la seine?")
229
-
230
- ### Proposer une nouvelle fonctionnalité
231
-
232
- N'hésitez pas :
233
-
234
- - Forker le dépôt
235
- - Créer un nouveau tool
236
- - Tester de votre côté
237
- - Faire une pull-request
238
-
239
-
240
-
241
- ## Crédits
242
-
243
- * [mcp-framework](https://mcp-framework.com) fournit le **cadre de développement du MCP** :
244
-
245
- ```bash
246
- # Par exemple, pour exposer la liste des couches WMTS
247
- mcp add tool gpf_wmts_layers
248
- ```
249
-
250
- * [@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.
251
- * [MiniSearch](https://github.com/lucaong/minisearch) pour la **recherche par mot clé** utilisée dans `@ignfab/gpf-schema-store`.
252
- * [jsts](https://bjornharrtell.github.io/jsts/) pour les **traitements géométriques** (ex : tri des réponses par distance au point recherché).
253
- * [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).
254
-
255
- ## Licence
256
-
257
- [MIT](LICENSE)
258
-
259
-
1
+ <p align="center">
2
+ <img src="docs/imgs/hexagon-geoctx.svg" alt="logo du projet geocontext" width="300">
3
+ </p>
4
+
5
+ # Geocontext
6
+
7
+ 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).
8
+
9
+ <details>
10
+ <summary>📋 Table des matières</summary>
11
+
12
+ - [Geocontext](#geocontext)
13
+ - [Motivation](#motivation)
14
+ - [Mises en garde](#mises-en-garde)
15
+ - [Principes de conception](#principes-de-conception)
16
+ - [Utilisation](#utilisation)
17
+ - [Utilisation de la version publiée](#utilisation-de-la-version-publiée)
18
+ - [Autres exemples d'utilisation](#autres-exemples-dutilisation)
19
+ - [Développement](#développement)
20
+ - [Construction de la version locale](#construction-de-la-version-locale)
21
+ - [Utilisation de la version locale](#utilisation-de-la-version-locale)
22
+ - [Avec un client MCP compatible JSON](#avec-un-client-mcp-compatible-json)
23
+ - [Avec Docker en local](#avec-docker-en-local)
24
+ - [Debug de la version locale](#debug-de-la-version-locale)
25
+ - [Paramétrage](#paramétrage)
26
+ - [Tests](#tests)
27
+ - [Fonctionnalités (Tools)](#fonctionnalités-tools)
28
+ - [Utiliser des services spatiaux](#utiliser-des-services-spatiaux)
29
+ - [Recherche d'informations pour un lieu](#recherche-dinformations-pour-un-lieu)
30
+ - [Explorer les données vecteurs](#explorer-les-données-vecteurs)
31
+ - [Explorer les tables](#explorer-les-tables)
32
+ - [Explorer la structure des tables](#explorer-la-structure-des-tables)
33
+ - [Explorer les données des tables](#explorer-les-données-des-tables)
34
+ - [Voir également](#voir-également)
35
+ - [Contribution](#contribution)
36
+ - [Problèmes et demandes d'évolutions](#problèmes-et-demandes-dévolutions)
37
+ - [Proposer une nouvelle fonctionnalité](#proposer-une-nouvelle-fonctionnalité)
38
+ - [Crédits](#crédits)
39
+ - [Licence](#licence)
40
+
41
+ </details>
42
+
43
+ ## Motivation
44
+
45
+ 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).
46
+
47
+ 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,...).
48
+
49
+ 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**.
50
+
51
+ ## Mises en garde
52
+
53
+ - 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)
54
+ - 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`)
55
+ - Les [issues](https://github.com/ignfab/geocontext/issues) sont régulièrement mises à jour et traitées
56
+ - Une [roadmap](https://github.com/ignfab/geocontext/wiki) est également régulièrement alimentée
57
+ - 🪄 Cet outil ne relève pas de la magie : ses capacités sont définies et documentées dans [Fonctionnalités](#fonctionnalités).
58
+
59
+ ## Principes de conception
60
+
61
+ - **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)
62
+ - **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.
63
+ - **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.
64
+
65
+ ## Utilisation
66
+
67
+ ### Utilisation de la version publiée
68
+
69
+ Par exemple, avec "Cursor Settings / MCP / Add server" :
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "geocontext": {
75
+ "command": "npx",
76
+ "args": ["-y", "@ignfab/geocontext"]
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### Autres exemples d'utilisation
83
+
84
+ - [Exemple d'utilisation avec Claude Desktop](docs/usage/claude-desktop.md)
85
+ - [Exemple d'utilisation avec MCPJam](docs/usage/mcpjam.md)
86
+
87
+ ## Développement
88
+
89
+ Pré-requis :
90
+
91
+ - Node.js `24.5.0` ou supérieur recommandé (`22.21.0` minimum supporté)
92
+ - npm compatible avec la version de Node utilisée
93
+
94
+ Le dépôt fournit `.nvmrc` et `.node-version`. Si vous utilisez `nvm`, vous pouvez donc faire :
95
+
96
+ ```bash
97
+ nvm install
98
+ nvm use
99
+ ```
100
+
101
+ ### Construction de la version locale
102
+
103
+ ```bash
104
+ git clone https://github.com/ignfab/geocontext
105
+ cd geocontext
106
+ npm ci
107
+ npm run build
108
+ ```
109
+
110
+ ### Utilisation de la version locale
111
+
112
+ #### Avec un client MCP compatible JSON
113
+
114
+ ```json
115
+ {
116
+ "mcpServers": {
117
+ "geocontext": {
118
+ "command": "node",
119
+ "args":["--use-env-proxy", "/chemin/absolu/vers/geocontext/dist/index.js"]
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ 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).
126
+
127
+ #### Avec Docker en local
128
+
129
+ ```bash
130
+ docker compose build
131
+ docker compose up -d
132
+ ```
133
+
134
+ Ensuite :
135
+
136
+ ```json
137
+ {
138
+ "mcpServers": {
139
+ "geocontext": {
140
+ "url": "http://localhost:3000/mcp"
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ ### Debug de la version locale
147
+
148
+ Cette commande lance **MCP Inspector**, l’outil de développement de MCP pour tester et déboguer un serveur local.
149
+
150
+ ```bash
151
+ npm run inspect:mcp
152
+ ```
153
+
154
+ Pour les tests d'intégration et les tests E2E agent, voir [la documentation dédiée](docs/testing/README.md).
155
+
156
+ ## Paramétrage
157
+
158
+ Pour une utilisation avancée :
159
+
160
+ | Nom | Description | Valeur par défaut |
161
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
162
+ | `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" |
163
+ | `HTTP_HOST` | Adresse d'écoute en mode HTTP. Utile avec Docker pour exposer le service via `0.0.0.0`. | "127.0.0.1" |
164
+ | `HTTP_PORT` | Port d'écoute du MCP | 3000 |
165
+ | `HTTP_MCP_ENDPOINT` | Chemin d'exposition du MCP en HTTP | "/mcp" |
166
+ | `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) |
167
+ | `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` |
168
+ | `GPF_WFS_RATE_LIMIT` | Nombre maximum de requêtes par seconde sur le WFS de la Géoplateforme | 30 |
169
+ | `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` |
170
+ | `LOG_FORMAT` | Le format d'écriture des logs : "json" ou "simple". | "simple" |
171
+ | `LOG_LEVEL` | Le niveau d'écriture des logs : ["error", "info", ou "debug"](https://github.com/winstonjs/winston#logging-levels) | "debug" |
172
+
173
+ Exemple :
174
+
175
+ ```bash
176
+ export GPF_WFS_MINISEARCH_OPTIONS='{"fields":["title","identifierTokens"],"combineWith":"OR","fuzzy":0.05,"boost":{"title":4,"name":5}}'
177
+ export HTTP_TIMEOUT=15
178
+ ```
179
+
180
+ 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`.
181
+
182
+ <a id="configuration-du-proxy-reseau"></a>
183
+ <details>
184
+ <summary>Configuration du proxy réseau</summary>
185
+
186
+ `geocontext` s'appuie sur la gestion native du proxy par Node.js.
187
+
188
+ - En exécution locale, le serveur démarre avec `node --use-env-proxy`
189
+ - Les tests d'intégration propagent `NODE_USE_ENV_PROXY=1` au sous-processus MCP lancé en `stdio`
190
+ - Les tests E2E démarrent les workers Vitest avec `--use-env-proxy`
191
+
192
+ Il suffit donc de définir les variables d'environnement standard selon votre contexte :
193
+
194
+ ```bash
195
+ export HTTP_PROXY=http://proxy.example:3128
196
+ export HTTPS_PROXY=http://proxy.example:3128
197
+ export NO_PROXY=localhost,127.0.0.1
198
+ ```
199
+
200
+ </details>
201
+
202
+ ### Tests
203
+
204
+ Les commandes principales sont :
205
+
206
+ ```bash
207
+ npm run typecheck
208
+ npm run typecheck:test
209
+ npm test
210
+ npm run test:integration
211
+ npm run test:e2e
212
+ npm run test:coverage
213
+ npm run verify
214
+ npm run verify:full
215
+ ```
216
+
217
+ `npm run verify:fast` inclut le type-check de l'application et des fichiers de test avant le build et les tests unitaires.
218
+
219
+ Remarque :
220
+
221
+ - 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`.
222
+ - Les outils `gpf_wfs_get_features` et `gpf_wfs_get_feature_by_id` interrogent toujours le service WFS de la Géoplateforme en direct.
223
+ - 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.
224
+
225
+ ## Fonctionnalités (Tools)
226
+
227
+ 👉 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).
228
+ On décrit ci-dessous succinctement les différents `tools` MCP proposés par `geocontext`.
229
+
230
+ ### Utiliser des services spatiaux
231
+
232
+ * [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)**.
233
+
234
+ > Ex : Quelle est la position (lon,lat) de la mairie de Vincennes?
235
+
236
+ * [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**.
237
+
238
+ > Ex : Quelle est l'altitude de la mairie de Loray (25)?
239
+
240
+ ### Recherche d'informations pour un lieu
241
+
242
+ 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/) :
243
+
244
+ * [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.
245
+
246
+ > Ex : Quelles sont les informations administratives pour la mairie de Vincennes?
247
+
248
+ * [cadastre(lon,lat)](src/tools/CadastreTool.ts) permet de **récupérer les informations cadastrales (parcelle, feuille,...)**.
249
+
250
+ > Ex : Quelles sont les informations du cadastre pour la mairie de Vincennes?
251
+
252
+ * [urbanisme(lon,lat)](src/tools/UrbanismeTool.ts) permet de **récupérer les informations d'urbanisme (PLU,POS,CC,PSMV)**
253
+
254
+ > Ex : Quel est le document PLU en vigueur pour le port de Marseille?
255
+
256
+ * [assiette_sup(lon,lat)](src/tools/AssietteSupTool.ts) permet de **récupérer les Servitudes d'Utilité Publique (SUP)**
257
+
258
+ > Ex: Quelles assiettes de SUP sont présentes autour de la mairie de Vincennes ?
259
+
260
+ 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"`).
261
+
262
+ ### Explorer les données vecteurs
263
+
264
+ #### Explorer les tables
265
+
266
+ * [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`.
267
+
268
+ > - Quels sont les millésimes ADMINEXPRESS disponibles sur la Géoplateforme?
269
+ > - Quelle est la table de la BDTOPO correspondant aux bâtiments?
270
+ > - Dans quelle table de la BDTOPO peut-on trouver les ponts?
271
+
272
+ #### Explorer la structure des tables
273
+
274
+ * [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`
275
+
276
+ > - Quelles sont les informations disponibles pour les communes avec ADMINEXPRESS-COG.LATEST?
277
+ > - Compare le modèle des communes entre ADMINEXPRESS-COG:2024 et ADMINEXPRESS-COG.LATEST
278
+
279
+ #### Explorer les données des tables
280
+
281
+ * [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`**.
282
+
283
+ Le tool accepte un contrat structuré :
284
+
285
+ - `select` pour choisir les propriétés à renvoyer
286
+ - `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)
287
+ - `result_type="results"` pour renvoyer une `FeatureCollection` normalisée contenant exactement un seul objet
288
+
289
+ Exemple :
290
+
291
+ - `typename="ADMINEXPRESS-COG.LATEST:commune", feature_id="commune.8952"`
292
+
293
+ * [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.
294
+
295
+ Le tool accepte un contrat structuré :
296
+
297
+ - `select` pour choisir les propriétés à renvoyer
298
+ - `where` pour filtrer les objets
299
+ - `order_by` pour trier les résultats
300
+ - `spatial_operator` et ses paramètres dédiés pour le spatial
301
+ - `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
302
+
303
+ Exemples :
304
+
305
+ - `where=[{ property: "code_insee", operator: "eq", value: "25000" }]`
306
+ - `spatial_operator="bbox"` avec `bbox_west`, `bbox_south`, `bbox_east`, `bbox_north`
307
+ - `spatial_operator="dwithin_point"` avec `dwithin_lon`, `dwithin_lat`, `dwithin_distance_m`
308
+ - `spatial_operator="intersects_feature"` avec `intersects_feature_typename` et `intersects_feature_id` issus d'une `feature_ref`
309
+
310
+ > - Quelles sont les 5 communes les plus peuplées du Doubs (25)?
311
+ > - Combien y a-t-il de bâtiments à moins de 5 km de la tour Eiffel?
312
+
313
+
314
+ ## Voir également
315
+
316
+ - https://github.com/datagouv/datagouv-mcp : MCP data.gouv.fr
317
+ - https://github.com/mapbox/mcp-server : MCP Mapbox
318
+ - https://git.tricoteuses.fr/logiciels/tricoteuses-api-parlement : MCP parlement français non officiel
319
+ - https://github.com/datagouv/datagouv-skill : Skills data.gouv.fr
320
+
321
+ ## Contribution
322
+
323
+ ### Problèmes et demandes d'évolutions
324
+
325
+ N'hésitez pas à [créer une issue](https://github.com/ignfab/geocontext/issues) si vous rencontrez un problème! Merci de fournir :
326
+
327
+ - L'assistant (ex: Github Copilot) et le modèle utilisé (ex: Claude Sonnet 4.5)
328
+ - La demande que vous faites à l'assistant (ex : "Combien y a-t-il de pont franchissant la Seine?")
329
+
330
+ ### Proposer une nouvelle fonctionnalité
331
+
332
+ N'hésitez pas :
333
+
334
+ - Forker le dépôt
335
+ - Créer un nouveau tool
336
+ - Tester de votre côté
337
+ - Faire une pull-request
338
+
339
+ ## Crédits
340
+
341
+ * [mcp-framework](https://mcp-framework.com) fournit le **cadre de développement du MCP**
342
+ * [@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.
343
+ * [MiniSearch](https://github.com/lucaong/minisearch) pour la **recherche par mot clé** utilisée dans `@ignfab/gpf-schema-store`.
344
+ * [jsts](https://bjornharrtell.github.io/jsts/) pour les **traitements géométriques** (ex : tri des réponses par distance au point recherché).
345
+ * [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).
346
+
347
+ ## Licence
348
+
349
+ [MIT](LICENSE)