Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/mcp-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ Lecture d’objets GPF
```
Interroge un type GPF et renvoie des résultats structurés (propriétés attributaires ; les géométries ne sont pas incluses). Pour obtenir une couche cartographiable, utiliser `gpf_get_features_layer`.
Utiliser `select` pour choisir les propriétés, `where` pour filtrer, `order_by` pour trier et un filtre spatial dédié (`bbox_filter`, `intersects_point_filter`, `dwithin_point_filter`, `intersects_feature_filter` ou `travel_time_filter`) pour le spatial.
Utiliser `spatial_extras` pour obtenir des mesures calculées sur la géométrie (`centroid`, `bbox`, `length`, `area`, `distance_to_filter` et `intersection_area`). Elles portent uniquement sur les objets renvoyés.
Exemple attributaire : `where=[{ property: "code_insee", operator: "eq", value: "75056" }]`.
Exemple bbox : `bbox_filter={ west: 2.1, south: 48.7, east: 2.5, north: 48.9 }`.
Exemple point dans géométrie : `intersects_point_filter={ lon: 2.35, lat: 48.85 }`.
Expand All @@ -1117,7 +1118,7 @@ Les noms de propriétés **ne peuvent pas être devinés** : ils sont spécifiqu
| `limit` | integer | non | Nombre maximum d'objets à renvoyer. Valeur par défaut : 100. Maximum : 5000. Valeur par défaut : 100. |
| `order_by` | array | non | Liste ordonnée des critères de tri. |
| `select` | array | non | Liste des propriétés non géométriques à renvoyer pour chaque objet. Utiliser `gpf_describe_type` pour connaître les noms exacts disponibles. Exemple : `["code_insee", "nom_officiel"]`. |
| `spatial_extras` | array | non | Éléments calculés depuis la géométrie à renvoyer pour chaque objet. Peut inclure `centroid`, `bbox`, `length`, `area`, `distance_to_filter` et `intersection_area`, aucun par défaut.<br>`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.<br>`bbox` est la boîte englobante de la géométrie.<br>`length` est renvoyé en m et ne peut être utilisé qu'avec des géométries linéaires (LineString, MultiLineString).<br>`area` est renvoyé en m² et ne peut être utilisé qu'avec des géométries surfaciques (Polygon, MultiPolygon).<br>`distance_to_filter` est la distance (en m) entre la géométrie de l'objet renvoyé et le centroïde du filtre spatial (le point de départ dans le cas de `travel_time_filter`).<br>`intersection_area` est l'aire d'intersection (en m²) entre la géométrie de l'objet renvoyé, qui doit être surfacique, et le filtre spatial.<br>Si l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.<br>Si une valeur n'est pas calculable pour une autre raison, elle sera remplacée par `null` dans la réponse. Valeur par défaut : []. |
| `spatial_extras` | array | non | Éléments calculés depuis la géométrie à renvoyer pour chaque objet. Peut inclure `centroid`, `bbox`, `length`, `area`, `distance_to_filter` et `intersection_area`, aucun par défaut.<br>`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.<br>`bbox` est la boîte englobante de la géométrie.<br>`length` est la somme des longueurs (en m) des parties linéaires de la géométrie (LineString, MultiLineString).<br>`area` est la somme des surfaces (en m²) des parties surfaciques de la géométrie (Polygon, MultiPolygon).<br>`distance_to_filter` est la distance (en m) entre la géométrie de l'objet renvoyé et le centroïde du filtre spatial (le point de départ dans le cas de `travel_time_filter`).<br>`intersection_area` est l'aire (en m²) de la partie de l'objet renvoyé située dans le filtre spatial. L'objet et le filtre doivent être surfaciques, sinon la valeur est `null` ; `0` signifie que l'objet ne recouvre pas le filtre.<br>`distance_to_filter` et `intersection_area` exigent un filtre spatial.<br>Les `spatial_extras` sont calculés après la requête, sur les seuls objets renvoyés : ils ne sont utilisables ni dans `where` ni dans `order_by`. Pour un classement (les N plus grands, le plus proche) ou une somme, vérifier que `numberReturned` est égal à `numberMatched`, sinon augmenter `limit`.<br>Si l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.<br>Sinon, un élément qui n'est pas calculable pour un objet (géométrie absente ou vide, aucune partie de la dimension requise) vaut `null`. Une valeur numérique, `0` compris, signifie que le calcul a bien eu lieu. Valeur par défaut : []. |
| `travel_time_filter` | object | non | Filtre spatial par temps de trajet depuis un point (`profile` voiture ou piéton). Exclusif avec les autres filtres spatiaux. |
| `typename` | string | oui | Nom exact du type GPF à interroger de la forme `prefixe:nom`. Utiliser `gpf_search_types` pour trouver un `typename` valide. |
| `where` | array | non | Clauses de filtre attributaire, combinées avec `AND`. |
Expand Down Expand Up @@ -1391,7 +1392,7 @@ Les noms de propriétés **ne peuvent pas être devinés** : ils sont spécifiqu
]
},
"default": [],
"description": "Éléments calculés depuis la géométrie à renvoyer pour chaque objet. Peut inclure `centroid`, `bbox`, `length`, `area`, `distance_to_filter` et `intersection_area`, aucun par défaut.\n`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.\n`bbox` est la boîte englobante de la géométrie.\n`length` est renvoyé en m et ne peut être utilisé qu'avec des géométries linéaires (LineString, MultiLineString).\n`area` est renvoyé en m² et ne peut être utilisé qu'avec des géométries surfaciques (Polygon, MultiPolygon).\n`distance_to_filter` est la distance (en m) entre la géométrie de l'objet renvoyé et le centroïde du filtre spatial (le point de départ dans le cas de `travel_time_filter`).\n`intersection_area` est l'aire d'intersection (en m²) entre la géométrie de l'objet renvoyé, qui doit être surfacique, et le filtre spatial.\nSi l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.\nSi une valeur n'est pas calculable pour une autre raison, elle sera remplacée par `null` dans la réponse."
"description": "Éléments calculés depuis la géométrie à renvoyer pour chaque objet. Peut inclure `centroid`, `bbox`, `length`, `area`, `distance_to_filter` et `intersection_area`, aucun par défaut.\n`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.\n`bbox` est la boîte englobante de la géométrie.\n`length` est la somme des longueurs (en m) des parties linéaires de la géométrie (LineString, MultiLineString).\n`area` est la somme des surfaces (en m²) des parties surfaciques de la géométrie (Polygon, MultiPolygon).\n`distance_to_filter` est la distance (en m) entre la géométrie de l'objet renvoyé et le centroïde du filtre spatial (le point de départ dans le cas de `travel_time_filter`).\n`intersection_area` est l'aire (en m²) de la partie de l'objet renvoyé située dans le filtre spatial. L'objet et le filtre doivent être surfaciques, sinon la valeur est `null` ; `0` signifie que l'objet ne recouvre pas le filtre.\n`distance_to_filter` et `intersection_area` exigent un filtre spatial.\nLes `spatial_extras` sont calculés après la requête, sur les seuls objets renvoyés : ils ne sont utilisables ni dans `where` ni dans `order_by`. Pour un classement (les N plus grands, le plus proche) ou une somme, vérifier que `numberReturned` est égal à `numberMatched`, sinon augmenter `limit`.\nSi l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.\nSinon, un élément qui n'est pas calculable pour un objet (géométrie absente ou vide, aucune partie de la dimension requise) vaut `null`. Une valeur numérique, `0` compris, signifie que le calcul a bien eu lieu."
}
},
"required": [
Expand Down Expand Up @@ -2060,7 +2061,7 @@ Utiliser `spatial_extras` pour renvoyer une information géométrique dérivée
| --- | --- | --- | --- |
| `feature_id` | string | oui | Identifiant GPF exact de l'objet à récupérer, par exemple `commune.8952`. |
| `select` | array | non | Liste des propriétés non géométriques à renvoyer. Utiliser `gpf_describe_type` pour connaître les noms exacts disponibles. Exemple : `["code_insee", "nom_officiel"]`. |
| `spatial_extras` | array | non | Éléments calculés depuis la géométrie à renvoyer pour l'objet. Peut inclure `centroid`, `bbox`, `length` et `area`, aucun par défaut.<br>`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.<br>`bbox` est la boîte englobante de la géométrie.<br>`length` est renvoyé en m et ne peut être utilisé qu'avec des géométries linéaires (LineString, MultiLineString).<br>`area` est renvoyé en m² et ne peut être utilisé qu'avec des géométries surfaciques (Polygon, MultiPolygon).<br>Si l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.<br>Si une valeur n'est pas calculable pour une autre raison, elle sera remplacée par `null` dans la réponse. Valeur par défaut : []. |
| `spatial_extras` | array | non | Éléments calculés depuis la géométrie à renvoyer pour l'objet. Peut inclure `centroid`, `bbox`, `length` et `area`, aucun par défaut.<br>`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.<br>`bbox` est la boîte englobante de la géométrie.<br>`length` est la somme des longueurs (en m) des parties linéaires de la géométrie (LineString, MultiLineString).<br>`area` est la somme des surfaces (en m²) des parties surfaciques de la géométrie (Polygon, MultiPolygon).<br>Si l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.<br>Sinon, un élément qui n'est pas calculable pour un objet (géométrie absente ou vide, aucune partie de la dimension requise) vaut `null`. Une valeur numérique, `0` compris, signifie que le calcul a bien eu lieu. Valeur par défaut : []. |
| `typename` | string | oui | Nom exact du type GPF à interroger, par exemple `ADMINEXPRESS-COG.LATEST:commune`. |

<details>
Expand Down Expand Up @@ -2101,7 +2102,7 @@ Utiliser `spatial_extras` pour renvoyer une information géométrique dérivée
]
},
"default": [],
"description": "Éléments calculés depuis la géométrie à renvoyer pour l'objet. Peut inclure `centroid`, `bbox`, `length` et `area`, aucun par défaut.\n`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.\n`bbox` est la boîte englobante de la géométrie.\n`length` est renvoyé en m et ne peut être utilisé qu'avec des géométries linéaires (LineString, MultiLineString).\n`area` est renvoyé en m² et ne peut être utilisé qu'avec des géométries surfaciques (Polygon, MultiPolygon).\nSi l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.\nSi une valeur n'est pas calculable pour une autre raison, elle sera remplacée par `null` dans la réponse."
"description": "Éléments calculés depuis la géométrie à renvoyer pour l'objet. Peut inclure `centroid`, `bbox`, `length` et `area`, aucun par défaut.\n`centroid` est le centroïde (moyenne arithmétique des sommets) de la géométrie.\n`bbox` est la boîte englobante de la géométrie.\n`length` est la somme des longueurs (en m) des parties linéaires de la géométrie (LineString, MultiLineString).\n`area` est la somme des surfaces (en m²) des parties surfaciques de la géométrie (Polygon, MultiPolygon).\nSi l'élément à calculer est incompatible avec la géométrie (exemple : bbox d'un point, aire d'une géométrie linéaire) et que le type de la géométrie est connu à l'avance, une erreur indiquera comment corriger la requête.\nSinon, un élément qui n'est pas calculable pour un objet (géométrie absente ou vide, aucune partie de la dimension requise) vaut `null`. Une valeur numérique, `0` compris, signifie que le calcul a bien eu lieu."
}
},
"required": [
Expand Down
2 changes: 2 additions & 0 deletions src/tools/GpfGetFeaturesTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
type GpfGetFeaturesInput,
gpfGetFeaturesPublishedInputSchema,
GPF_SPATIAL_FILTER_DOCNAMES,
GPF_SPATIAL_EXTRAS_DOCNAMES,
} from "../wfs/schema.js";
import logger from "../logger.js";

Expand All @@ -25,6 +26,7 @@ import logger from "../logger.js";
const GPF_GET_FEATURES_TOOL_DESCRIPTION = [
"Interroge un type GPF et renvoie des résultats structurés (propriétés attributaires ; les géométries ne sont pas incluses). Pour obtenir une couche cartographiable, utiliser `gpf_get_features_layer`.",
`Utiliser \`select\` pour choisir les propriétés, \`where\` pour filtrer, \`order_by\` pour trier et un filtre spatial dédié (${GPF_SPATIAL_FILTER_DOCNAMES}) pour le spatial.`,
`Utiliser \`spatial_extras\` pour obtenir des mesures calculées sur la géométrie (${GPF_SPATIAL_EXTRAS_DOCNAMES}). Elles portent uniquement sur les objets renvoyés.`,
"Exemple attributaire : `where=[{ property: \"code_insee\", operator: \"eq\", value: \"75056\" }]`.",
"Exemple bbox : `bbox_filter={ west: 2.1, south: 48.7, east: 2.5, north: 48.9 }`.",
"Exemple point dans géométrie : `intersects_point_filter={ lon: 2.35, lat: 48.85 }`.",
Expand Down
12 changes: 9 additions & 3 deletions src/wfs/properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import type { GpfFeatureType } from "./catalog.js";
import type { OgcCollectionProperty } from "@ignfab/gpf-schema-store";
import type { Geometry } from "geojson";
import type { SpatialExtraOptions } from "./schema.js";
import { GPF_GET_FEATURES_SPATIAL_EXTRAS, type SpatialExtraOptions } from "./schema.js";

// --- Geometry Resolution ---

Expand Down Expand Up @@ -99,8 +99,12 @@ export function resolveNonGeometryProperty(featureType: GpfFeatureType, property
const nonGeometryProperties = (Object.entries(featureType.schema.properties))
.filter(([_propertyName, property]) => Boolean((property as OgcCollectionProperty).type))
.map(([propertyName]) => propertyName);
// A spatial extra name is a likely mix-up (e.g. `order_by: area`): say what it is.
const spatialExtraHint = (GPF_GET_FEATURES_SPATIAL_EXTRAS as readonly string[]).includes(propertyName)
? ` \`${propertyName}\` désigne un élément calculé par \`spatial_extras\` dans \`gpf_get_features\`, pas une propriété du type : il n'est utilisable ni dans \`select\`, ni dans \`where\`, ni dans \`order_by\`.`
: "";
throw new Error(
`La propriété '${propertyName}' n'existe pas pour '${featureType.typename}'. ` +
`La propriété '${propertyName}' n'existe pas pour '${featureType.typename}'.${spatialExtraHint} ` +
`Propriétés non géométriques disponibles : ${nonGeometryProperties.join(", ")}. ` +
`Appelle \`gpf_describe_type\` pour obtenir la signification de ces propriétés.`,
);
Expand Down Expand Up @@ -132,7 +136,9 @@ export function validateSelectProperty(featureType: GpfFeatureType, propertyName
// --- Spatial Extras Validation ---

function validateSpatialExtras(featureType: GpfFeatureType, geometryName: string, spatial_extras?: SpatialExtraOptions[]) {
if (!spatial_extras) {
// Nothing to validate without extras: do not read the geometry format, which
// cartographic callers (always `[]`) never need.
if (!spatial_extras?.length) {
return;
}
const geometryType = getGeometryType(featureType, geometryName);
Expand Down
7 changes: 0 additions & 7 deletions src/wfs/queryPreparation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import type {
import {
GPF_SPATIAL_FILTER_DOCNAMES,
queryIsGetFeaturesInput,
spatialExtraRequiresFilter,
} from "./schema.js"

import {
Expand Down Expand Up @@ -188,7 +187,6 @@ export function compileQueryParts(
let geometryName: string | undefined;
const isGetFeatures = queryIsGetFeaturesInput(input);
const spatialFilter = getSpatialFilter(input);
const spatialExtras = isGetFeatures ? input.spatial_extras : [];
const fragments: string[] = [];

// Keep the spatial predicate first: the GeoPlateforme GeoServer is sensitive
Expand Down Expand Up @@ -221,11 +219,6 @@ export function compileQueryParts(
const noFilter: never = spatialFilter;
throw new Error(`Unhandled filter case: ${noFilter}`);
}
} else if (spatialExtras.length > 0) {
const faultyExtra = spatialExtras.filter(spatialExtraRequiresFilter);
if (faultyExtra.length > 0) {
throw new Error(`Impossible de demander ${faultyExtra} sans spécifier de filtre géométrique (à choisir parmi ${GPF_SPATIAL_FILTER_DOCNAMES}).`);
}
}

for (const clause of input.where ?? []) {
Expand Down
Loading