@ignfab/geocontext 0.9.3 → 0.9.5

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 (75) hide show
  1. package/README.md +46 -28
  2. package/dist/gpf/adminexpress.js +7 -27
  3. package/dist/gpf/adminexpress.js.map +1 -1
  4. package/dist/gpf/parcellaire-express.js +13 -33
  5. package/dist/gpf/parcellaire-express.js.map +1 -1
  6. package/dist/gpf/urbanisme.d.ts +4 -2
  7. package/dist/gpf/urbanisme.js +20 -61
  8. package/dist/gpf/urbanisme.js.map +1 -1
  9. package/dist/gpf/wfs.d.ts +2 -2
  10. package/dist/gpf/wfs.js +17 -71
  11. package/dist/gpf/wfs.js.map +1 -1
  12. package/dist/helpers/distance.d.ts +4 -2
  13. package/dist/helpers/distance.js +20 -5
  14. package/dist/helpers/distance.js.map +1 -1
  15. package/dist/helpers/http.d.ts +4 -0
  16. package/dist/helpers/http.js +103 -1
  17. package/dist/helpers/http.js.map +1 -1
  18. package/dist/helpers/jsonSchema.d.ts +3 -0
  19. package/dist/helpers/jsonSchema.js +8 -0
  20. package/dist/helpers/jsonSchema.js.map +1 -0
  21. package/dist/helpers/schemas.d.ts +13 -0
  22. package/dist/helpers/schemas.js +18 -0
  23. package/dist/helpers/schemas.js.map +1 -0
  24. package/dist/helpers/wfs.d.ts +27 -0
  25. package/dist/helpers/wfs.js +55 -0
  26. package/dist/helpers/wfs.js.map +1 -0
  27. package/dist/helpers/wfs_internal/compile.d.ts +46 -0
  28. package/dist/helpers/wfs_internal/compile.js +595 -0
  29. package/dist/helpers/wfs_internal/compile.js.map +1 -0
  30. package/dist/helpers/wfs_internal/request.d.ts +38 -0
  31. package/dist/helpers/wfs_internal/request.js +92 -0
  32. package/dist/helpers/wfs_internal/request.js.map +1 -0
  33. package/dist/helpers/wfs_internal/response.d.ts +21 -0
  34. package/dist/helpers/wfs_internal/response.js +29 -0
  35. package/dist/helpers/wfs_internal/response.js.map +1 -0
  36. package/dist/helpers/wfs_internal/schema.d.ts +167 -0
  37. package/dist/helpers/wfs_internal/schema.js +81 -0
  38. package/dist/helpers/wfs_internal/schema.js.map +1 -0
  39. package/dist/index.js +47 -25
  40. package/dist/index.js.map +1 -1
  41. package/dist/tools/AdminexpressTool.d.ts +52 -2
  42. package/dist/tools/AdminexpressTool.js +11 -14
  43. package/dist/tools/AdminexpressTool.js.map +1 -1
  44. package/dist/tools/AltitudeTool.d.ts +2 -2
  45. package/dist/tools/AltitudeTool.js +4 -13
  46. package/dist/tools/AltitudeTool.js.map +1 -1
  47. package/dist/tools/AssietteSupTool.d.ts +55 -3
  48. package/dist/tools/AssietteSupTool.js +12 -15
  49. package/dist/tools/AssietteSupTool.js.map +1 -1
  50. package/dist/tools/CadastreTool.d.ts +52 -2
  51. package/dist/tools/CadastreTool.js +13 -15
  52. package/dist/tools/CadastreTool.js.map +1 -1
  53. package/dist/tools/GeocodeTool.d.ts +2 -2
  54. package/dist/tools/GeocodeTool.js +6 -4
  55. package/dist/tools/GeocodeTool.js.map +1 -1
  56. package/dist/tools/GpfWfsDescribeTypeTool.d.ts +16 -16
  57. package/dist/tools/GpfWfsDescribeTypeTool.js +4 -3
  58. package/dist/tools/GpfWfsDescribeTypeTool.js.map +1 -1
  59. package/dist/tools/GpfWfsGetFeaturesTool.d.ts +170 -44
  60. package/dist/tools/GpfWfsGetFeaturesTool.js +161 -114
  61. package/dist/tools/GpfWfsGetFeaturesTool.js.map +1 -1
  62. package/dist/tools/GpfWfsSearchTypesTool.d.ts +8 -2
  63. package/dist/tools/GpfWfsSearchTypesTool.js +12 -9
  64. package/dist/tools/GpfWfsSearchTypesTool.js.map +1 -1
  65. package/dist/tools/UrbanismeTool.d.ts +53 -3
  66. package/dist/tools/UrbanismeTool.js +9 -15
  67. package/dist/tools/UrbanismeTool.js.map +1 -1
  68. package/package.json +8 -7
  69. package/dist/resources/WfsCqlFilterResource.d.ts +0 -10
  70. package/dist/resources/WfsCqlFilterResource.js +0 -23
  71. package/dist/resources/WfsCqlFilterResource.js.map +0 -1
  72. package/dist/resources/content/wfs-cql-filter.md +0 -215
  73. package/dist/tools/GpfWfsListTypesTool.d.ts +0 -22
  74. package/dist/tools/GpfWfsListTypesTool.js +0 -26
  75. package/dist/tools/GpfWfsListTypesTool.js.map +0 -1
@@ -1,28 +1,7 @@
1
1
  import { MCPTool } from "mcp-framework";
2
- import { z } from "zod";
3
- declare const gpfWfsGetFeaturesInputSchema: z.ZodObject<{
4
- typename: z.ZodString;
5
- property_names: z.ZodOptional<z.ZodString>;
6
- sort_by: z.ZodOptional<z.ZodString>;
7
- count: z.ZodOptional<z.ZodNumber>;
8
- cql_filter: z.ZodOptional<z.ZodString>;
9
- result_type: z.ZodOptional<z.ZodEnum<["results", "hits", "url"]>>;
10
- }, "strip", z.ZodTypeAny, {
11
- cql_filter?: string;
12
- typename?: string;
13
- property_names?: string;
14
- sort_by?: string;
15
- count?: number;
16
- result_type?: "results" | "hits" | "url";
17
- }, {
18
- cql_filter?: string;
19
- typename?: string;
20
- property_names?: string;
21
- sort_by?: string;
22
- count?: number;
23
- result_type?: "results" | "hits" | "url";
24
- }>;
25
- type GpfWfsGetFeaturesInput = z.infer<typeof gpfWfsGetFeaturesInputSchema>;
2
+ import type { Collection } from "@ignfab/gpf-schema-store";
3
+ import { type CompiledRequest } from "../helpers/wfs_internal/request.js";
4
+ import { type GpfWfsGetFeaturesInput } from "../helpers/wfs_internal/schema.js";
26
5
  declare class GpfWfsGetFeaturesTool extends MCPTool<GpfWfsGetFeaturesInput> {
27
6
  name: string;
28
7
  title: string;
@@ -33,28 +12,121 @@ declare class GpfWfsGetFeaturesTool extends MCPTool<GpfWfsGetFeaturesInput> {
33
12
  openWorldHint: boolean;
34
13
  };
35
14
  description: string;
36
- schema: z.ZodObject<{
37
- typename: z.ZodString;
38
- property_names: z.ZodOptional<z.ZodString>;
39
- sort_by: z.ZodOptional<z.ZodString>;
40
- count: z.ZodOptional<z.ZodNumber>;
41
- cql_filter: z.ZodOptional<z.ZodString>;
42
- result_type: z.ZodOptional<z.ZodEnum<["results", "hits", "url"]>>;
43
- }, "strip", z.ZodTypeAny, {
44
- cql_filter?: string;
15
+ schema: import("zod").ZodObject<{
16
+ typename: import("zod").ZodString;
17
+ limit: import("zod").ZodDefault<import("zod").ZodNumber>;
18
+ result_type: import("zod").ZodDefault<import("zod").ZodEnum<["results", "hits", "request"]>>;
19
+ select: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
20
+ order_by: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
21
+ property: import("zod").ZodString;
22
+ direction: import("zod").ZodDefault<import("zod").ZodEnum<["asc", "desc"]>>;
23
+ }, "strict", import("zod").ZodTypeAny, {
24
+ property?: string;
25
+ direction?: "asc" | "desc";
26
+ }, {
27
+ property?: string;
28
+ direction?: "asc" | "desc";
29
+ }>, "many">>;
30
+ where: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
31
+ property: import("zod").ZodString;
32
+ operator: import("zod").ZodEnum<["eq", "ne", "lt", "lte", "gt", "gte", "in", "is_null"]>;
33
+ value: import("zod").ZodOptional<import("zod").ZodString>;
34
+ values: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
35
+ }, "strict", import("zod").ZodTypeAny, {
36
+ values?: string[];
37
+ value?: string;
38
+ property?: string;
39
+ operator?: "gte" | "gt" | "lte" | "lt" | "eq" | "ne" | "in" | "is_null";
40
+ }, {
41
+ values?: string[];
42
+ value?: string;
43
+ property?: string;
44
+ operator?: "gte" | "gt" | "lte" | "lt" | "eq" | "ne" | "in" | "is_null";
45
+ }>, "many">>;
46
+ spatial_operator: import("zod").ZodOptional<import("zod").ZodEnum<["bbox", "intersects_point", "dwithin_point", "intersects_feature"]>>;
47
+ bbox_west: import("zod").ZodOptional<import("zod").ZodNumber>;
48
+ bbox_south: import("zod").ZodOptional<import("zod").ZodNumber>;
49
+ bbox_east: import("zod").ZodOptional<import("zod").ZodNumber>;
50
+ bbox_north: import("zod").ZodOptional<import("zod").ZodNumber>;
51
+ intersects_lon: import("zod").ZodOptional<import("zod").ZodNumber>;
52
+ intersects_lat: import("zod").ZodOptional<import("zod").ZodNumber>;
53
+ dwithin_lon: import("zod").ZodOptional<import("zod").ZodNumber>;
54
+ dwithin_lat: import("zod").ZodOptional<import("zod").ZodNumber>;
55
+ dwithin_distance_m: import("zod").ZodOptional<import("zod").ZodNumber>;
56
+ intersects_feature_typename: import("zod").ZodOptional<import("zod").ZodString>;
57
+ intersects_feature_id: import("zod").ZodOptional<import("zod").ZodString>;
58
+ }, "strict", import("zod").ZodTypeAny, {
45
59
  typename?: string;
46
- property_names?: string;
47
- sort_by?: string;
48
- count?: number;
49
- result_type?: "results" | "hits" | "url";
60
+ limit?: number;
61
+ result_type?: "request" | "results" | "hits";
62
+ select?: string[];
63
+ order_by?: {
64
+ property?: string;
65
+ direction?: "asc" | "desc";
66
+ }[];
67
+ where?: {
68
+ values?: string[];
69
+ value?: string;
70
+ property?: string;
71
+ operator?: "gte" | "gt" | "lte" | "lt" | "eq" | "ne" | "in" | "is_null";
72
+ }[];
73
+ spatial_operator?: "bbox" | "intersects_point" | "dwithin_point" | "intersects_feature";
74
+ bbox_west?: number;
75
+ bbox_south?: number;
76
+ bbox_east?: number;
77
+ bbox_north?: number;
78
+ intersects_lon?: number;
79
+ intersects_lat?: number;
80
+ dwithin_lon?: number;
81
+ dwithin_lat?: number;
82
+ dwithin_distance_m?: number;
83
+ intersects_feature_typename?: string;
84
+ intersects_feature_id?: string;
50
85
  }, {
51
- cql_filter?: string;
52
86
  typename?: string;
53
- property_names?: string;
54
- sort_by?: string;
55
- count?: number;
56
- result_type?: "results" | "hits" | "url";
87
+ limit?: number;
88
+ result_type?: "request" | "results" | "hits";
89
+ select?: string[];
90
+ order_by?: {
91
+ property?: string;
92
+ direction?: "asc" | "desc";
93
+ }[];
94
+ where?: {
95
+ values?: string[];
96
+ value?: string;
97
+ property?: string;
98
+ operator?: "gte" | "gt" | "lte" | "lt" | "eq" | "ne" | "in" | "is_null";
99
+ }[];
100
+ spatial_operator?: "bbox" | "intersects_point" | "dwithin_point" | "intersects_feature";
101
+ bbox_west?: number;
102
+ bbox_south?: number;
103
+ bbox_east?: number;
104
+ bbox_north?: number;
105
+ intersects_lon?: number;
106
+ intersects_lat?: number;
107
+ dwithin_lon?: number;
108
+ dwithin_lat?: number;
109
+ dwithin_distance_m?: number;
110
+ intersects_feature_typename?: string;
111
+ intersects_feature_id?: string;
57
112
  }>;
113
+ /**
114
+ * Exposes an input schema variant that stays compatible with most MCP integrations.
115
+ *
116
+ * @returns The published input schema exposed through the MCP tool definition.
117
+ */
118
+ get inputSchema(): {
119
+ type: "object";
120
+ properties?: Record<string, object>;
121
+ required?: string[];
122
+ };
123
+ /**
124
+ * Formats compact responses (`hits`, `request`) into `structuredContent`.
125
+ * Full result sets are still delegated to the framework default behavior.
126
+ *
127
+ * @param data Raw execution result returned by the tool implementation.
128
+ * @returns An MCP success response, optionally enriched with structured content.
129
+ */
58
130
  protected createSuccessResponse(data: unknown): import("mcp-framework").ToolResponse | {
59
131
  content: {
60
132
  type: "text";
@@ -70,10 +142,64 @@ declare class GpfWfsGetFeaturesTool extends MCPTool<GpfWfsGetFeaturesInput> {
70
142
  text: string;
71
143
  }[];
72
144
  structuredContent: {
145
+ body?: string;
146
+ result_type?: "request";
147
+ method?: "POST";
73
148
  url?: string;
74
- result_type?: "url";
149
+ query?: Record<string, string>;
150
+ get_url?: string;
75
151
  };
76
152
  };
77
- execute(input: GpfWfsGetFeaturesInput): Promise<any>;
153
+ /**
154
+ * Loads a WFS feature type description from the embedded catalog.
155
+ *
156
+ * @param typename Exact WFS typename to load from the embedded schema store.
157
+ * @returns The matching feature type description.
158
+ */
159
+ protected getFeatureType(typename: string): Promise<Collection>;
160
+ /**
161
+ * Executes a compiled WFS request as POST and returns the JSON FeatureCollection.
162
+ *
163
+ * @param request Compiled request split into query-string parameters and POST body.
164
+ * @returns The parsed JSON response returned by the WFS endpoint.
165
+ */
166
+ protected fetchFeatureCollection(request: CompiledRequest): Promise<any>;
167
+ /**
168
+ * Extracts a result count from a WFS response, preferring `numberMatched`.
169
+ * Explicitly rejects responses that do not provide a usable total.
170
+ *
171
+ * @param featureCollection Parsed WFS response object.
172
+ * @returns The total number of matching features.
173
+ */
174
+ protected getMatchedFeatureCount(featureCollection: Record<string, unknown>): number;
175
+ /**
176
+ * Enriches transformed features with a complete `feature_ref`, reusable
177
+ * in particular by `intersects_feature`.
178
+ *
179
+ * @param featureCollection Raw WFS FeatureCollection response.
180
+ * @param typename Typename of the main queried layer.
181
+ * @returns The transformed FeatureCollection with fully populated feature references.
182
+ */
183
+ protected attachFeatureRefs(featureCollection: Record<string, unknown>, typename: string): Record<string, unknown>;
184
+ /**
185
+ * Resolves the geometry of a reference feature when `intersects_feature` is used,
186
+ * then converts it to EWKT for CQL compilation.
187
+ *
188
+ * @param input Normalized tool input.
189
+ * @returns The resolved reference geometry, or `undefined` when no reference feature is needed.
190
+ */
191
+ protected resolveIntersectsFeatureGeometry(input: GpfWfsGetFeaturesInput): Promise<{
192
+ typename: string;
193
+ feature_id: string;
194
+ geometry_ewkt: string;
195
+ }>;
196
+ /**
197
+ * Orchestrates the full tool execution flow:
198
+ * catalog lookup -> compilation -> WFS request -> response post-processing.
199
+ *
200
+ * @param input Normalized tool input.
201
+ * @returns Either a compiled request, a hit count, or a transformed FeatureCollection.
202
+ */
203
+ execute(input: GpfWfsGetFeaturesInput): Promise<Record<string, unknown>>;
78
204
  }
79
205
  export default GpfWfsGetFeaturesTool;
@@ -1,76 +1,40 @@
1
1
  import { MCPTool } from "mcp-framework";
2
- import { z } from "zod";
3
- import { GPF_WFS_URL } from "../gpf/wfs.js";
4
- import { fetchJSON } from "../helpers/http.js";
2
+ import { wfsClient } from "../gpf/wfs.js";
3
+ import { fetchJSONPost } from "../helpers/http.js";
5
4
  import logger from "../logger.js";
6
5
  import { READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS } from "../helpers/toolAnnotations.js";
7
- // This tool intentionally does not expose a single outputSchemaShape.
8
- // - `result_type="results"` can return a large FeatureCollection, and we
9
- // avoid duplicating that payload into structuredContent.
10
- // - Compact modes (`hits`, `url`) are handled explicitly in createSuccessResponse().
11
- const gpfWfsGetFeaturesInputSchema = z.object({
12
- typename: z
13
- .string()
14
- .trim()
15
- .min(1, "le nom du type ne doit pas être vide")
16
- .describe("L'identifiant exact du type WFS à interroger (ex : `BDTOPO_V3:batiment`). Ce paramètre détermine la collection interrogée et doit correspondre à un type valide. Utiliser `gpf_wfs_search_types` pour trouver un `typename` pertinent, puis `gpf_wfs_describe_type` pour inspecter ses propriétés avant la requête."),
17
- property_names: z
18
- .string()
19
- .optional()
20
- .describe("La liste des propriétés à inclure dans chaque objet renvoyé, séparées par des virgules (ex : \"code_insee,nom_officiel,geometrie\"). Ce paramètre limite les champs présents dans la réponse, sans filtrer les objets eux-mêmes. Les noms doivent correspondre exactement aux propriétés du type WFS ; utiliser `gpf_wfs_describe_type` pour les connaître."),
21
- sort_by: z
22
- .string()
23
- .optional()
24
- .describe("Les propriétés à utiliser pour trier les objets renvoyés, avec la syntaxe `field [A|D]` où `A` signifie tri ascendant et `D` tri descendant. Plusieurs critères peuvent être séparés par des virgules (ex : `nom_officiel A, population D`). Les noms doivent correspondre exactement aux propriétés du type WFS ; utiliser `gpf_wfs_describe_type` pour les connaître."),
25
- count: z
26
- .number()
27
- .int()
28
- .min(1)
29
- .max(1000)
30
- .optional()
31
- .describe("Le nombre maximum d'objets à retourner dans la réponse (entre 1 et 1000). Ce paramètre limite les résultats renvoyés, sans modifier le nombre total d'objets correspondant à la requête. Il est surtout utile avec `result_type=\"results\"`."),
32
- cql_filter: z
33
- .string()
34
- .optional()
35
- .describe([
36
- "Un filtre `cql_filter` GeoServer pour restreindre les objets renvoyés par la requête.",
37
- "Il faut utiliser les noms exacts des propriétés du type WFS ; utiliser `gpf_wfs_describe_type` pour les connaître.",
38
- "Attention : en `EPSG:4326`, les coordonnées des géométries doivent être exprimées en `lat lon` (y x), y compris pour les points, lignes et polygones.",
39
- "Exemples :",
40
- "- filtre attributaire : `code_insee = '75056'`",
41
- "- filtre spatial point : `DWITHIN(geom,Point(48.8566 2.3522),100,meters)`",
42
- "- filtre spatial polygone : `INTERSECTS(geom,POLYGON((48.85 2.34,48.86 2.34,48.86 2.36,48.85 2.36,48.85 2.34)))`",
43
- ].join("\r\n")),
44
- result_type: z
45
- .enum(["results", "hits", "url"])
46
- .optional()
47
- .describe([
48
- "Choisit le type de résultat renvoyé par le tool :",
49
- "- `results` : retourne les objets trouvés sous forme de `FeatureCollection` GeoJSON complète (défaut)",
50
- "- `hits` : retourne uniquement le nombre total d'objets correspondant à la requête",
51
- "- `url` : retourne uniquement l'URL WFS construite pour la requête, utile pour inspection, débogage ou réutilisation côté client",
52
- ].join("\r\n"))
53
- });
54
- const gpfWfsGetFeaturesHitsOutputSchema = z.object({
55
- result_type: z.literal("hits").describe("Indique que la réponse contient uniquement un comptage."),
56
- totalFeatures: z.number().describe("Le nombre total d'objets correspondant à la requête."),
57
- });
58
- const gpfWfsGetFeaturesUrlOutputSchema = z.object({
59
- result_type: z.literal("url").describe("Indique que la réponse contient uniquement l'URL de la requête."),
60
- url: z.string().describe("L'URL WFS générée pour la requête."),
61
- });
6
+ import { compileQueryParts, geometryToEwkt, getGeometryProperty, getSpatialFilter } from "../helpers/wfs_internal/compile.js";
7
+ import { buildMainRequest, buildReferenceGeometryRequest } from "../helpers/wfs_internal/request.js";
8
+ import { transformFeatureCollectionResponse } from "../helpers/wfs_internal/response.js";
9
+ import { gpfWfsGetFeaturesHitsOutputSchema, gpfWfsGetFeaturesInputSchema, gpfWfsGetFeaturesPublishedInputSchema, gpfWfsGetFeaturesRequestOutputSchema, } from "../helpers/wfs_internal/schema.js";
62
10
  class GpfWfsGetFeaturesTool extends MCPTool {
63
11
  name = "gpf_wfs_get_features";
64
12
  title = "Lecture d’objets WFS";
65
13
  annotations = READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS;
66
14
  description = [
67
- "Récupère les objets d'un type WFS à partir d'un `typename` valide, avec filtres, tri et sélection de propriétés optionnels.",
68
- "Exécute une requête WFS sur un type connu (`typename`) et renvoie soit les objets trouvés, soit leur nombre total, soit l'URL WFS correspondante.",
69
- "Utiliser `gpf_wfs_search_types` puis `gpf_wfs_describe_type` avant ce tool lorsque le type ou ses propriétés ne sont pas connus.",
70
- "Le paramètre `result_type` permet de récupérer soit les données complètes (`results`), soit uniquement le comptage (`hits`), soit l'URL WFS générée (`url`).",
71
- "Les paramètres optionnels permettent de filtrer, trier ou restreindre les champs et le nombre d'objets renvoyés.",
72
- ].join("\r\n");
15
+ "Interroge un type WFS et renvoie des résultats structurés sans demander au modèle d'écrire du CQL ou du WFS.",
16
+ "Utiliser `select` pour choisir les propriétés, `where` pour filtrer, `order_by` pour trier et `spatial_operator` avec ses paramètres dédiés pour le spatial. Avec `result_type=\"request\"`, la géométrie est automatiquement ajoutée aux propriétés sélectionnées pour garantir une requête cartographiable.",
17
+ "Exemple attributaire : `where=[{ property: \"code_insee\", operator: \"eq\", value: \"75056\" }]`.",
18
+ "Exemple bbox : `spatial_operator=\"bbox\"` avec `bbox_west`, `bbox_south`, `bbox_east`, `bbox_north` en `lon/lat`.",
19
+ "Exemple distance : `spatial_operator=\"dwithin_point\"` avec `dwithin_lon`, `dwithin_lat`, `dwithin_distance_m`.",
20
+ "Exemple réutilisation : `spatial_operator=\"intersects_feature\"` avec `intersects_feature_typename` et `intersects_feature_id` issus d'une `feature_ref`.",
21
+ ].join("\n");
73
22
  schema = gpfWfsGetFeaturesInputSchema;
23
+ /**
24
+ * Exposes an input schema variant that stays compatible with most MCP integrations.
25
+ *
26
+ * @returns The published input schema exposed through the MCP tool definition.
27
+ */
28
+ get inputSchema() {
29
+ return gpfWfsGetFeaturesPublishedInputSchema;
30
+ }
31
+ /**
32
+ * Formats compact responses (`hits`, `request`) into `structuredContent`.
33
+ * Full result sets are still delegated to the framework default behavior.
34
+ *
35
+ * @param data Raw execution result returned by the tool implementation.
36
+ * @returns An MCP success response, optionally enriched with structured content.
37
+ */
74
38
  createSuccessResponse(data) {
75
39
  if (typeof data === "object" &&
76
40
  data !== null &&
@@ -79,80 +43,163 @@ class GpfWfsGetFeaturesTool extends MCPTool {
79
43
  "totalFeatures" in data &&
80
44
  typeof data.totalFeatures === "number") {
81
45
  return {
82
- content: [
83
- {
84
- type: "text",
85
- text: JSON.stringify(data.totalFeatures),
86
- },
87
- ],
46
+ content: [{ type: "text", text: JSON.stringify(data.totalFeatures) }],
88
47
  structuredContent: gpfWfsGetFeaturesHitsOutputSchema.parse(data),
89
48
  };
90
49
  }
91
50
  if (typeof data === "object" &&
92
51
  data !== null &&
93
52
  "result_type" in data &&
94
- data.result_type === "url" &&
95
- "url" in data &&
96
- typeof data.url === "string") {
53
+ data.result_type === "request") {
97
54
  return {
98
- content: [
99
- {
100
- type: "text",
101
- text: data.url,
102
- },
103
- ],
104
- structuredContent: gpfWfsGetFeaturesUrlOutputSchema.parse(data),
55
+ content: [{ type: "text", text: JSON.stringify(data) }],
56
+ structuredContent: gpfWfsGetFeaturesRequestOutputSchema.parse(data),
105
57
  };
106
58
  }
107
59
  return super.createSuccessResponse(data);
108
60
  }
109
- async execute(input) {
110
- const params = {
111
- service: 'WFS',
112
- request: 'GetFeature',
113
- typeName: input.typename,
114
- outputFormat: 'application/json'
115
- };
116
- // Only add optional parameters if they are defined
117
- if (input.cql_filter) {
118
- params.cql_filter = input.cql_filter;
61
+ /**
62
+ * Loads a WFS feature type description from the embedded catalog.
63
+ *
64
+ * @param typename Exact WFS typename to load from the embedded schema store.
65
+ * @returns The matching feature type description.
66
+ */
67
+ async getFeatureType(typename) {
68
+ return wfsClient.getFeatureType(typename);
69
+ }
70
+ /**
71
+ * Executes a compiled WFS request as POST and returns the JSON FeatureCollection.
72
+ *
73
+ * @param request Compiled request split into query-string parameters and POST body.
74
+ * @returns The parsed JSON response returned by the WFS endpoint.
75
+ */
76
+ async fetchFeatureCollection(request) {
77
+ const url = `${request.url}?${new URLSearchParams(request.query).toString()}`;
78
+ return fetchJSONPost(url, request.body, {
79
+ "Content-Type": "application/x-www-form-urlencoded",
80
+ "Accept": "application/json",
81
+ });
82
+ }
83
+ /**
84
+ * Extracts a result count from a WFS response, preferring `numberMatched`.
85
+ * Explicitly rejects responses that do not provide a usable total.
86
+ *
87
+ * @param featureCollection Parsed WFS response object.
88
+ * @returns The total number of matching features.
89
+ */
90
+ getMatchedFeatureCount(featureCollection) {
91
+ if (typeof featureCollection.numberMatched === "number") {
92
+ return featureCollection.numberMatched;
119
93
  }
120
- if (input.count) {
121
- params.count = String(input.count);
94
+ if (featureCollection.numberMatched === "unknown") {
95
+ throw new Error("Le service WFS a renvoyé un comptage indéterminé (numberMatched=\"unknown\").");
122
96
  }
123
- if (input.sort_by) {
124
- params.sortBy = input.sort_by;
97
+ if (typeof featureCollection.totalFeatures === "number") {
98
+ return featureCollection.totalFeatures;
99
+ }
100
+ throw new Error("Le service WFS n'a pas retourné de comptage exploitable");
101
+ }
102
+ /**
103
+ * Enriches transformed features with a complete `feature_ref`, reusable
104
+ * in particular by `intersects_feature`.
105
+ *
106
+ * @param featureCollection Raw WFS FeatureCollection response.
107
+ * @param typename Typename of the main queried layer.
108
+ * @returns The transformed FeatureCollection with fully populated feature references.
109
+ */
110
+ attachFeatureRefs(featureCollection, typename) {
111
+ const transformed = transformFeatureCollectionResponse(featureCollection);
112
+ if (!Array.isArray(transformed.features)) {
113
+ return transformed;
114
+ }
115
+ transformed.features = transformed.features.map((feature) => {
116
+ if (typeof feature !== "object" || feature === null || !("feature_ref" in feature)) {
117
+ return feature;
118
+ }
119
+ const featureRef = feature.feature_ref;
120
+ if (typeof featureRef !== "object" || featureRef === null) {
121
+ return feature;
122
+ }
123
+ return {
124
+ ...feature,
125
+ feature_ref: {
126
+ ...featureRef,
127
+ typename,
128
+ },
129
+ };
130
+ });
131
+ return transformed;
132
+ }
133
+ /**
134
+ * Resolves the geometry of a reference feature when `intersects_feature` is used,
135
+ * then converts it to EWKT for CQL compilation.
136
+ *
137
+ * @param input Normalized tool input.
138
+ * @returns The resolved reference geometry, or `undefined` when no reference feature is needed.
139
+ */
140
+ async resolveIntersectsFeatureGeometry(input) {
141
+ const spatialFilter = getSpatialFilter(input);
142
+ if (!spatialFilter || spatialFilter.operator !== "intersects_feature") {
143
+ return undefined;
125
144
  }
126
- if (input.property_names && input.property_names.length > 0) {
127
- params.propertyName = input.property_names;
145
+ const referenceFeatureType = await this.getFeatureType(spatialFilter.typename);
146
+ const referenceGeometryProperty = getGeometryProperty(referenceFeatureType);
147
+ const request = buildReferenceGeometryRequest(spatialFilter.typename, spatialFilter.feature_id, referenceGeometryProperty.name);
148
+ const featureCollection = await this.fetchFeatureCollection(request);
149
+ const referenceFeature = Array.isArray(featureCollection?.features) ? featureCollection.features[0] : undefined;
150
+ if (!referenceFeature) {
151
+ throw new Error(`Le feature de référence '${spatialFilter.feature_id}' est introuvable dans '${spatialFilter.typename}'.`);
128
152
  }
129
- // Si result_type est 'hits', on utilise count=1 pour récupérer juste le totalFeatures
130
- // On fait cela parce que Geoserver ne renvoie pas de json avec resultType=hits
131
- // On est obligé de faire une requete getfeature pour récupérer le totalFeatures...
132
- if (input.result_type === 'hits') {
133
- params.count = "1";
134
- // On n'a pas besoin des propriétés détaillées pour un comptage
135
- delete params.propertyName;
153
+ if (!referenceFeature?.geometry) {
154
+ throw new Error(`Le feature de référence '${spatialFilter.feature_id}' n'a pas de géométrie exploitable.`);
136
155
  }
137
- const url = `${GPF_WFS_URL}?` + new URLSearchParams(params).toString();
138
- logger.info(`[gpf_wfs_get_features] ${url}`);
139
- if (input.result_type === 'url') {
156
+ return {
157
+ typename: spatialFilter.typename,
158
+ feature_id: spatialFilter.feature_id,
159
+ geometry_ewkt: geometryToEwkt(referenceFeature.geometry),
160
+ };
161
+ }
162
+ /**
163
+ * Orchestrates the full tool execution flow:
164
+ * catalog lookup -> compilation -> WFS request -> response post-processing.
165
+ *
166
+ * @param input Normalized tool input.
167
+ * @returns Either a compiled request, a hit count, or a transformed FeatureCollection.
168
+ */
169
+ async execute(input) {
170
+ const featureType = await this.getFeatureType(input.typename);
171
+ const resolvedGeometryRef = await this.resolveIntersectsFeatureGeometry(input);
172
+ const compiled = compileQueryParts(input, featureType, resolvedGeometryRef);
173
+ const request = buildMainRequest(input, compiled);
174
+ if (input.result_type === "request") {
140
175
  return {
141
- result_type: "url",
142
- url,
176
+ result_type: "request",
177
+ method: request.method,
178
+ url: request.url,
179
+ query: request.query,
180
+ body: request.body,
181
+ get_url: request.get_url ?? null,
143
182
  };
144
183
  }
145
- const featureCollection = await fetchJSON(url);
146
- if (input.result_type === 'hits') {
147
- if (typeof featureCollection?.totalFeatures !== "number") {
148
- throw new Error("Le service WFS n'a pas retourné de comptage exploitable");
184
+ let featureCollection;
185
+ try {
186
+ logger.info(`[gpf_wfs_get_features] POST ${request.url}?${new URLSearchParams(request.query).toString()}`);
187
+ featureCollection = await this.fetchFeatureCollection(request);
188
+ }
189
+ catch (error) {
190
+ const message = error instanceof Error ? error.message : String(error);
191
+ if (message.includes(`Illegal property name: ${compiled.geometryProperty.name}`)) {
192
+ throw new Error(`Le champ géométrique '${compiled.geometryProperty.name}' issu du catalogue embarqué est rejeté par le WFS live pour '${input.typename}'. Le catalogue embarqué est probablement désynchronisé. Détail : ${message}`);
149
193
  }
194
+ throw error;
195
+ }
196
+ if (input.result_type === "hits") {
150
197
  return {
151
198
  result_type: "hits",
152
- totalFeatures: featureCollection.totalFeatures,
199
+ totalFeatures: this.getMatchedFeatureCount(featureCollection),
153
200
  };
154
201
  }
155
- return featureCollection;
202
+ return this.attachFeatureRefs(featureCollection, input.typename);
156
203
  }
157
204
  }
158
205
  export default GpfWfsGetFeaturesTool;
@@ -1 +1 @@
1
- {"version":3,"file":"GpfWfsGetFeaturesTool.js","sourceRoot":"","sources":["../../src/tools/GpfWfsGetFeaturesTool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"GpfWfsGetFeaturesTool.js","sourceRoot":"","sources":["../../src/tools/GpfWfsGetFeaturesTool.ts"],"names":[],"mappings":"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"}