@honua/mcp-server 0.1.2-beta.0 → 0.1.8-beta.0
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.
- package/LICENSE +201 -0
- package/README.md +232 -9
- package/dist/src/certification/admin-parity.d.ts +96 -0
- package/dist/src/certification/admin-parity.d.ts.map +1 -0
- package/dist/src/certification/admin-parity.js +235 -0
- package/dist/src/certification/census-fixture-client.d.ts.map +1 -1
- package/dist/src/certification/census-fixture-client.js +5 -0
- package/dist/src/certification/certifier.d.ts +1 -1
- package/dist/src/certification/certifier.d.ts.map +1 -1
- package/dist/src/certification/certifier.js +28 -20
- package/dist/src/certification/cli.js +1 -1
- package/dist/src/certification/cql2.d.ts +24 -0
- package/dist/src/certification/cql2.d.ts.map +1 -0
- package/dist/src/certification/cql2.js +354 -0
- package/dist/src/certification/fixtures.d.ts +8 -0
- package/dist/src/certification/fixtures.d.ts.map +1 -1
- package/dist/src/certification/fixtures.js +26 -10
- package/dist/src/certification/ogc-data.d.ts +30 -0
- package/dist/src/certification/ogc-data.d.ts.map +1 -0
- package/dist/src/certification/ogc-data.js +726 -0
- package/dist/src/certification/ogc-fixture-client.d.ts +4 -0
- package/dist/src/certification/ogc-fixture-client.d.ts.map +1 -0
- package/dist/src/certification/ogc-fixture-client.js +190 -0
- package/dist/src/certification/target.d.ts +10 -1
- package/dist/src/certification/target.d.ts.map +1 -1
- package/dist/src/certification/target.js +63 -28
- package/dist/src/credential-endpoint.d.ts +3 -0
- package/dist/src/credential-endpoint.d.ts.map +1 -0
- package/dist/src/credential-endpoint.js +24 -0
- package/dist/src/eval/cli.js +6 -3
- package/dist/src/eval/corpus.d.ts +7 -0
- package/dist/src/eval/corpus.d.ts.map +1 -1
- package/dist/src/eval/corpus.js +12 -0
- package/dist/src/eval/ogc-corpus.d.ts +3 -0
- package/dist/src/eval/ogc-corpus.d.ts.map +1 -0
- package/dist/src/eval/ogc-corpus.js +437 -0
- package/dist/src/eval/runner.d.ts +6 -0
- package/dist/src/eval/runner.d.ts.map +1 -1
- package/dist/src/eval/runner.js +21 -7
- package/dist/src/helpers.d.ts +8 -13
- package/dist/src/helpers.d.ts.map +1 -1
- package/dist/src/helpers.js +7 -35
- package/dist/src/index.d.ts +36 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +55 -18
- package/dist/src/neutral/errors.d.ts +73 -0
- package/dist/src/neutral/errors.d.ts.map +1 -0
- package/dist/src/neutral/errors.js +112 -0
- package/dist/src/neutral/filter.d.ts +108 -0
- package/dist/src/neutral/filter.d.ts.map +1 -0
- package/dist/src/neutral/filter.js +271 -0
- package/dist/src/neutral/query.d.ts +101 -0
- package/dist/src/neutral/query.d.ts.map +1 -0
- package/dist/src/neutral/query.js +180 -0
- package/dist/src/neutral/result.d.ts +33 -0
- package/dist/src/neutral/result.d.ts.map +1 -0
- package/dist/src/neutral/result.js +38 -0
- package/dist/src/neutral/source-ref.d.ts +126 -0
- package/dist/src/neutral/source-ref.d.ts.map +1 -0
- package/dist/src/neutral/source-ref.js +267 -0
- package/dist/src/nl-map-control.d.ts.map +1 -1
- package/dist/src/proxy.d.ts.map +1 -1
- package/dist/src/proxy.js +29 -14
- package/dist/src/release/zero-to-map-checkpoint.d.ts +34 -0
- package/dist/src/release/zero-to-map-checkpoint.d.ts.map +1 -0
- package/dist/src/release/zero-to-map-checkpoint.js +369 -0
- package/dist/src/release/zero-to-map-cli.d.ts +51 -0
- package/dist/src/release/zero-to-map-cli.d.ts.map +1 -0
- package/dist/src/release/zero-to-map-cli.js +880 -0
- package/dist/src/release/zero-to-map-provision.d.ts +37 -0
- package/dist/src/release/zero-to-map-provision.d.ts.map +1 -0
- package/dist/src/release/zero-to-map-provision.js +177 -0
- package/dist/src/release/zero-to-map.d.ts +296 -0
- package/dist/src/release/zero-to-map.d.ts.map +1 -0
- package/dist/src/release/zero-to-map.js +1069 -0
- package/dist/src/tools/admin-install-local.d.ts +30 -0
- package/dist/src/tools/admin-install-local.d.ts.map +1 -0
- package/dist/src/tools/admin-install-local.js +22 -0
- package/dist/src/tools/control-plane-command.d.ts +99 -0
- package/dist/src/tools/control-plane-command.d.ts.map +1 -0
- package/dist/src/tools/control-plane-command.js +180 -0
- package/dist/src/tools/count-features.d.ts +85 -11
- package/dist/src/tools/count-features.d.ts.map +1 -1
- package/dist/src/tools/count-features.js +49 -31
- package/dist/src/tools/describe-layer.d.ts +30 -6
- package/dist/src/tools/describe-layer.d.ts.map +1 -1
- package/dist/src/tools/describe-layer.js +99 -8
- package/dist/src/tools/docs-search.d.ts +100 -0
- package/dist/src/tools/docs-search.d.ts.map +1 -0
- package/dist/src/tools/docs-search.js +381 -0
- package/dist/src/tools/get-extent.d.ts +69 -11
- package/dist/src/tools/get-extent.d.ts.map +1 -1
- package/dist/src/tools/get-extent.js +28 -46
- package/dist/src/tools/list-services.d.ts +7 -0
- package/dist/src/tools/list-services.d.ts.map +1 -1
- package/dist/src/tools/list-services.js +8 -1
- package/dist/src/tools/list-sources.d.ts +44 -0
- package/dist/src/tools/list-sources.d.ts.map +1 -0
- package/dist/src/tools/list-sources.js +138 -0
- package/dist/src/tools/query-features.d.ts +99 -19
- package/dist/src/tools/query-features.d.ts.map +1 -1
- package/dist/src/tools/query-features.js +38 -45
- package/dist/src/tools/statistics.d.ts +80 -12
- package/dist/src/tools/statistics.d.ts.map +1 -1
- package/dist/src/tools/statistics.js +56 -23
- package/package.json +37 -8
- package/release/zero-to-map/README.md +174 -0
- package/release/zero-to-map/configs/claude-code.mcp.json +11 -0
- package/release/zero-to-map/configs/claude-desktop.json +11 -0
- package/release/zero-to-map/configs/cursor.json +11 -0
- package/release/zero-to-map/contracts/aws-ecs-provision-binding.schema.json +59 -0
- package/release/zero-to-map/contracts/checkpoint.schema.json +152 -0
- package/release/zero-to-map/contracts/console-receipt.schema.json +150 -0
- package/release/zero-to-map/contracts/esri-gp-mcp.v1.json +73 -0
- package/release/zero-to-map/fixtures/parcels.geojson +33 -0
- package/release/zero-to-map/fixtures/zoning.geojson +24 -0
- package/release/zero-to-map/journey.v1.json +1248 -0
|
@@ -1,26 +1,77 @@
|
|
|
1
1
|
import type { HonuaClient } from "@honua/sdk-js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* `honua_get_extent` — protocol-neutral bounding box (#1005).
|
|
5
|
+
*
|
|
6
|
+
* Runs the canonical `Source.queryExtent()`. Protocols with no server-side
|
|
7
|
+
* extent operation (OGC API Features, STAC, OData) answer from the collection's
|
|
8
|
+
* declared extent under the degraded capability policy, and say so; protocols
|
|
9
|
+
* that cannot answer at all refuse with a structured capability error.
|
|
10
|
+
*/
|
|
3
11
|
export declare const schema: z.ZodObject<{
|
|
4
|
-
|
|
5
|
-
layerId: z.ZodNumber;
|
|
12
|
+
filter: z.ZodOptional<z.ZodType<import("../neutral/filter.js").FilterNode, z.ZodTypeDef, import("../neutral/filter.js").FilterNode>>;
|
|
6
13
|
where: z.ZodOptional<z.ZodString>;
|
|
14
|
+
bbox: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
15
|
+
bboxSrid: z.ZodOptional<z.ZodNumber>;
|
|
7
16
|
geometry: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
8
17
|
geometryType: z.ZodOptional<z.ZodEnum<["esriGeometryPoint", "esriGeometryPolyline", "esriGeometryPolygon", "esriGeometryEnvelope", "esriGeometryMultipoint"]>>;
|
|
9
|
-
spatialRel: z.ZodOptional<z.ZodEnum<["intersects", "contains", "within"]>>;
|
|
18
|
+
spatialRel: z.ZodOptional<z.ZodEnum<["intersects", "contains", "within", "crosses", "touches", "overlaps", "bbox-intersects"]>>;
|
|
19
|
+
temporal: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
instant: z.ZodOptional<z.ZodString>;
|
|
21
|
+
start: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
22
|
+
end: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
23
|
+
field: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, "strip", z.ZodTypeAny, {
|
|
25
|
+
field?: string | undefined;
|
|
26
|
+
instant?: string | undefined;
|
|
27
|
+
start?: string | null | undefined;
|
|
28
|
+
end?: string | null | undefined;
|
|
29
|
+
}, {
|
|
30
|
+
field?: string | undefined;
|
|
31
|
+
instant?: string | undefined;
|
|
32
|
+
start?: string | null | undefined;
|
|
33
|
+
end?: string | null | undefined;
|
|
34
|
+
}>>;
|
|
35
|
+
source: z.ZodOptional<z.ZodString>;
|
|
36
|
+
layout: z.ZodOptional<z.ZodEnum<["honua-facade", "ogc-api", "auto", "stac-api", "stac-static"]>>;
|
|
37
|
+
serviceId: z.ZodOptional<z.ZodString>;
|
|
38
|
+
layerId: z.ZodOptional<z.ZodNumber>;
|
|
10
39
|
}, "strip", z.ZodTypeAny, {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
where?: string | undefined;
|
|
40
|
+
filter?: import("../neutral/filter.js").FilterNode | undefined;
|
|
41
|
+
serviceId?: string | undefined;
|
|
14
42
|
geometry?: Record<string, unknown> | undefined;
|
|
43
|
+
bbox?: number[] | undefined;
|
|
15
44
|
geometryType?: "esriGeometryPoint" | "esriGeometryPolyline" | "esriGeometryPolygon" | "esriGeometryEnvelope" | "esriGeometryMultipoint" | undefined;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
45
|
+
temporal?: {
|
|
46
|
+
field?: string | undefined;
|
|
47
|
+
instant?: string | undefined;
|
|
48
|
+
start?: string | null | undefined;
|
|
49
|
+
end?: string | null | undefined;
|
|
50
|
+
} | undefined;
|
|
51
|
+
layout?: "honua-facade" | "ogc-api" | "auto" | "stac-api" | "stac-static" | undefined;
|
|
52
|
+
layerId?: number | undefined;
|
|
53
|
+
source?: string | undefined;
|
|
20
54
|
where?: string | undefined;
|
|
55
|
+
bboxSrid?: number | undefined;
|
|
56
|
+
spatialRel?: "intersects" | "contains" | "within" | "crosses" | "touches" | "overlaps" | "bbox-intersects" | undefined;
|
|
57
|
+
}, {
|
|
58
|
+
filter?: import("../neutral/filter.js").FilterNode | undefined;
|
|
59
|
+
serviceId?: string | undefined;
|
|
21
60
|
geometry?: Record<string, unknown> | undefined;
|
|
61
|
+
bbox?: number[] | undefined;
|
|
22
62
|
geometryType?: "esriGeometryPoint" | "esriGeometryPolyline" | "esriGeometryPolygon" | "esriGeometryEnvelope" | "esriGeometryMultipoint" | undefined;
|
|
23
|
-
|
|
63
|
+
temporal?: {
|
|
64
|
+
field?: string | undefined;
|
|
65
|
+
instant?: string | undefined;
|
|
66
|
+
start?: string | null | undefined;
|
|
67
|
+
end?: string | null | undefined;
|
|
68
|
+
} | undefined;
|
|
69
|
+
layout?: "honua-facade" | "ogc-api" | "auto" | "stac-api" | "stac-static" | undefined;
|
|
70
|
+
layerId?: number | undefined;
|
|
71
|
+
source?: string | undefined;
|
|
72
|
+
where?: string | undefined;
|
|
73
|
+
bboxSrid?: number | undefined;
|
|
74
|
+
spatialRel?: "intersects" | "contains" | "within" | "crosses" | "touches" | "overlaps" | "bbox-intersects" | undefined;
|
|
24
75
|
}>;
|
|
25
76
|
export type Input = z.infer<typeof schema>;
|
|
26
77
|
export declare function execute(client: HonuaClient, input: Input): Promise<{
|
|
@@ -28,5 +79,12 @@ export declare function execute(client: HonuaClient, input: Input): Promise<{
|
|
|
28
79
|
type: "text";
|
|
29
80
|
text: string;
|
|
30
81
|
}>;
|
|
82
|
+
} | {
|
|
83
|
+
structuredContent: Record<string, unknown>;
|
|
84
|
+
isError: true;
|
|
85
|
+
content: Array<{
|
|
86
|
+
type: "text";
|
|
87
|
+
text: string;
|
|
88
|
+
}>;
|
|
31
89
|
}>;
|
|
32
90
|
//# sourceMappingURL=get-extent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-extent.d.ts","sourceRoot":"","sources":["../../../src/tools/get-extent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"get-extent.d.ts","sourceRoot":"","sources":["../../../src/tools/get-extent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE3C,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;;;;;;;;GAgB9D"}
|
|
@@ -1,51 +1,33 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { jsonText } from "../helpers.js";
|
|
3
|
+
import { withCapabilityHonesty } from "../neutral/errors.js";
|
|
4
|
+
import { queryFilterFields, toQuery } from "../neutral/query.js";
|
|
5
|
+
import { resolveSource, sourceRefFields } from "../neutral/source-ref.js";
|
|
6
|
+
/**
|
|
7
|
+
* `honua_get_extent` — protocol-neutral bounding box (#1005).
|
|
8
|
+
*
|
|
9
|
+
* Runs the canonical `Source.queryExtent()`. Protocols with no server-side
|
|
10
|
+
* extent operation (OGC API Features, STAC, OData) answer from the collection's
|
|
11
|
+
* declared extent under the degraded capability policy, and say so; protocols
|
|
12
|
+
* that cannot answer at all refuse with a structured capability error.
|
|
13
|
+
*/
|
|
3
14
|
export const schema = z.object({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
where: z.string().optional().describe("SQL WHERE clause"),
|
|
7
|
-
geometry: z.record(z.unknown()).optional().describe("Esri JSON geometry for spatial filter"),
|
|
8
|
-
geometryType: z
|
|
9
|
-
.enum(GEOMETRY_TYPES)
|
|
10
|
-
.optional()
|
|
11
|
-
.describe("Esri geometry type. If omitted, inferred from geometry when possible."),
|
|
12
|
-
spatialRel: z
|
|
13
|
-
.enum(["intersects", "contains", "within"])
|
|
14
|
-
.optional()
|
|
15
|
-
.describe("Spatial relationship (default: intersects)"),
|
|
15
|
+
...sourceRefFields,
|
|
16
|
+
...queryFilterFields,
|
|
16
17
|
});
|
|
17
18
|
export async function execute(client, input) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (!hasExtent) {
|
|
33
|
-
// Some backends can return count-only payloads for empty extent queries.
|
|
34
|
-
if (count !== undefined) {
|
|
35
|
-
return jsonText({ extent: null, count });
|
|
36
|
-
}
|
|
37
|
-
throw new Error("Extent query did not return an extent payload.");
|
|
38
|
-
}
|
|
39
|
-
let extent;
|
|
40
|
-
if (response.extent === null) {
|
|
41
|
-
extent = null;
|
|
42
|
-
}
|
|
43
|
-
else if (typeof response.extent === "object" && !Array.isArray(response.extent)) {
|
|
44
|
-
// A JSON array is `typeof "object"` but is not a valid extent envelope.
|
|
45
|
-
extent = response.extent;
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
throw new Error("Extent query returned an invalid extent payload.");
|
|
49
|
-
}
|
|
50
|
-
return jsonText({ extent, count });
|
|
19
|
+
return withCapabilityHonesty(async () => {
|
|
20
|
+
const resolved = resolveSource(client, input);
|
|
21
|
+
const query = toQuery(input, { protocol: resolved.descriptor.protocol, paginate: false });
|
|
22
|
+
const { extent, count } = await resolved.source.queryExtent(query);
|
|
23
|
+
return jsonText({
|
|
24
|
+
source: resolved.ref.ref,
|
|
25
|
+
protocol: resolved.descriptor.protocol,
|
|
26
|
+
extent: extent ?? null,
|
|
27
|
+
count: count ?? null,
|
|
28
|
+
// An extent that did not come from a server-side extent operation is an
|
|
29
|
+
// honest, but weaker, answer; name the capability so the caller can tell.
|
|
30
|
+
extentCapability: resolved.source.capabilities.has("queryExtent") ? "server" : "declared-extent",
|
|
31
|
+
});
|
|
32
|
+
});
|
|
51
33
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { HonuaClient } from "@honua/sdk-js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* `honua_list_services` — the GeoServices-specific service catalog.
|
|
5
|
+
*
|
|
6
|
+
* Retained for existing clients; `honua_list_sources` is the protocol-neutral
|
|
7
|
+
* replacement (#1005), because "what services are under /rest/services?" is a
|
|
8
|
+
* question only an Esri endpoint can answer.
|
|
9
|
+
*/
|
|
3
10
|
export declare const schema: z.ZodObject<{
|
|
4
11
|
includeDetails: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
5
12
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-services.d.ts","sourceRoot":"","sources":["../../../src/tools/list-services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,MAAM;;;;;;EAQjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAI3C,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;GA+C9D"}
|
|
1
|
+
{"version":3,"file":"list-services.d.ts","sourceRoot":"","sources":["../../../src/tools/list-services.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;;;;;;EAQjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAI3C,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;GA+C9D"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { jsonText, mapWithConcurrency, metadataErrorText } from "../helpers.js";
|
|
3
|
+
/**
|
|
4
|
+
* `honua_list_services` — the GeoServices-specific service catalog.
|
|
5
|
+
*
|
|
6
|
+
* Retained for existing clients; `honua_list_sources` is the protocol-neutral
|
|
7
|
+
* replacement (#1005), because "what services are under /rest/services?" is a
|
|
8
|
+
* question only an Esri endpoint can answer.
|
|
9
|
+
*/
|
|
3
10
|
export const schema = z.object({
|
|
4
11
|
includeDetails: z
|
|
5
12
|
.boolean()
|
|
@@ -22,7 +29,7 @@ export async function execute(client, input) {
|
|
|
22
29
|
catalogAvailable: false,
|
|
23
30
|
services: [],
|
|
24
31
|
reason: `service catalog is not available on this target: ${err instanceof Error ? err.message : String(err)}`,
|
|
25
|
-
guidance: "No /rest/services directory here
|
|
32
|
+
guidance: "No /rest/services directory here — this tool only sees a GeoServices catalog. Call honua_list_sources, which probes every protocol family this endpoint may publish (OGC API Features included) and returns protocol-neutral source references.",
|
|
26
33
|
});
|
|
27
34
|
}
|
|
28
35
|
const services = (response.services ?? []).filter((s) => s.type === "FeatureServer");
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { HonuaClient } from "@honua/sdk-js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* `honua_list_sources` — protocol-neutral discovery (#1005).
|
|
5
|
+
*
|
|
6
|
+
* `honua_list_services` answers a GeoServices-only question ("what is in
|
|
7
|
+
* `/rest/services`?"). This tool answers the neutral one — "what sources can I
|
|
8
|
+
* query here, and how do I address them?" — and emits the exact
|
|
9
|
+
* `<protocol>:<address>` references every other tool accepts, so an agent never
|
|
10
|
+
* has to construct one.
|
|
11
|
+
*
|
|
12
|
+
* Each protocol family is probed independently and degrades on its own: an
|
|
13
|
+
* endpoint that serves OGC collections but has no `/rest/services` directory
|
|
14
|
+
* reports the GeoServices family as unavailable-with-reason and still returns
|
|
15
|
+
* its OGC sources. A family that is absent is never reported as "no sources".
|
|
16
|
+
*/
|
|
17
|
+
export declare const schema: z.ZodObject<{
|
|
18
|
+
protocol: z.ZodDefault<z.ZodOptional<z.ZodEnum<["auto", "geoservices", "ogc-features", "ogc-records"]>>>;
|
|
19
|
+
layout: z.ZodOptional<z.ZodEnum<["honua-facade", "ogc-api", "auto", "stac-api", "stac-static"]>>;
|
|
20
|
+
maxServices: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
21
|
+
}, "strip", z.ZodTypeAny, {
|
|
22
|
+
protocol: "ogc-features" | "ogc-records" | "geoservices" | "auto";
|
|
23
|
+
maxServices: number;
|
|
24
|
+
layout?: "honua-facade" | "ogc-api" | "auto" | "stac-api" | "stac-static" | undefined;
|
|
25
|
+
}, {
|
|
26
|
+
layout?: "honua-facade" | "ogc-api" | "auto" | "stac-api" | "stac-static" | undefined;
|
|
27
|
+
protocol?: "ogc-features" | "ogc-records" | "geoservices" | "auto" | undefined;
|
|
28
|
+
maxServices?: number | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
export type Input = z.infer<typeof schema>;
|
|
31
|
+
export declare function execute(client: HonuaClient, input: Input): Promise<{
|
|
32
|
+
content: Array<{
|
|
33
|
+
type: "text";
|
|
34
|
+
text: string;
|
|
35
|
+
}>;
|
|
36
|
+
} | {
|
|
37
|
+
structuredContent: Record<string, unknown>;
|
|
38
|
+
isError: true;
|
|
39
|
+
content: Array<{
|
|
40
|
+
type: "text";
|
|
41
|
+
text: string;
|
|
42
|
+
}>;
|
|
43
|
+
}>;
|
|
44
|
+
//# sourceMappingURL=list-sources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sources.d.ts","sourceRoot":"","sources":["../../../src/tools/list-sources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;EAoBjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AA6F3C,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;;;;;;;;GAkC9D"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PROTOCOL_DEFAULT_CAPABILITIES } from "@honua/sdk-js/contract";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { jsonText, mapWithConcurrency } from "../helpers.js";
|
|
4
|
+
import { withCapabilityHonesty } from "../neutral/errors.js";
|
|
5
|
+
import { SOURCE_LAYOUTS, ogcLayoutFor } from "../neutral/source-ref.js";
|
|
6
|
+
/**
|
|
7
|
+
* `honua_list_sources` — protocol-neutral discovery (#1005).
|
|
8
|
+
*
|
|
9
|
+
* `honua_list_services` answers a GeoServices-only question ("what is in
|
|
10
|
+
* `/rest/services`?"). This tool answers the neutral one — "what sources can I
|
|
11
|
+
* query here, and how do I address them?" — and emits the exact
|
|
12
|
+
* `<protocol>:<address>` references every other tool accepts, so an agent never
|
|
13
|
+
* has to construct one.
|
|
14
|
+
*
|
|
15
|
+
* Each protocol family is probed independently and degrades on its own: an
|
|
16
|
+
* endpoint that serves OGC collections but has no `/rest/services` directory
|
|
17
|
+
* reports the GeoServices family as unavailable-with-reason and still returns
|
|
18
|
+
* its OGC sources. A family that is absent is never reported as "no sources".
|
|
19
|
+
*/
|
|
20
|
+
export const schema = z.object({
|
|
21
|
+
protocol: z
|
|
22
|
+
.enum(["auto", "geoservices", "ogc-features", "ogc-records"])
|
|
23
|
+
.optional()
|
|
24
|
+
.default("auto")
|
|
25
|
+
.describe("Restrict discovery to one protocol family. `auto` (default) probes every family this server can list."),
|
|
26
|
+
layout: z
|
|
27
|
+
.enum(SOURCE_LAYOUTS)
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Endpoint layout for the OGC families: "honua-facade" (default) or "ogc-api"/"auto" for a third-party OGC API root.'),
|
|
30
|
+
maxServices: z
|
|
31
|
+
.number()
|
|
32
|
+
.int()
|
|
33
|
+
.positive()
|
|
34
|
+
.max(200)
|
|
35
|
+
.optional()
|
|
36
|
+
.default(25)
|
|
37
|
+
.describe("Maximum GeoServices services expanded into per-layer sources (each costs one metadata request)."),
|
|
38
|
+
});
|
|
39
|
+
const METADATA_CONCURRENCY = 8;
|
|
40
|
+
function capabilitiesFor(protocol) {
|
|
41
|
+
return [...PROTOCOL_DEFAULT_CAPABILITIES[protocol]].sort();
|
|
42
|
+
}
|
|
43
|
+
async function discoverGeoServices(client, maxServices) {
|
|
44
|
+
let response;
|
|
45
|
+
try {
|
|
46
|
+
response = await client.listServices();
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
return {
|
|
50
|
+
available: false,
|
|
51
|
+
reason: `no GeoServices catalog on this target: ${err instanceof Error ? err.message : String(err)}`,
|
|
52
|
+
sources: [],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const services = (response.services ?? []).filter((s) => s.type === "FeatureServer" || s.type === "MapServer");
|
|
56
|
+
const expanded = services.slice(0, maxServices);
|
|
57
|
+
const perService = await mapWithConcurrency(expanded, METADATA_CONCURRENCY, async (service) => {
|
|
58
|
+
const protocol = service.type === "MapServer" ? "geoservices-map-service" : "geoservices-feature-service";
|
|
59
|
+
try {
|
|
60
|
+
const meta = await client.getFeatureServiceMetadata(service.name);
|
|
61
|
+
const layers = [...(meta.layers ?? []), ...(meta.tables ?? [])];
|
|
62
|
+
return layers.map((layer) => ({
|
|
63
|
+
source: `${protocol}:${service.name}/${layer.id}`,
|
|
64
|
+
protocol,
|
|
65
|
+
title: layer.name ?? null,
|
|
66
|
+
capabilities: capabilitiesFor(protocol),
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// The service exists but its metadata is unreadable; still emit the
|
|
71
|
+
// conventional layer-0 reference rather than dropping the service.
|
|
72
|
+
return [
|
|
73
|
+
{
|
|
74
|
+
source: `${protocol}:${service.name}/0`,
|
|
75
|
+
protocol,
|
|
76
|
+
title: service.name,
|
|
77
|
+
capabilities: capabilitiesFor(protocol),
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return { available: true, sources: perService.flat() };
|
|
83
|
+
}
|
|
84
|
+
async function discoverOgc(client, family, layout) {
|
|
85
|
+
try {
|
|
86
|
+
const resolved = await ogcLayoutFor(client, layout);
|
|
87
|
+
const request = resolved ? { layout: resolved } : {};
|
|
88
|
+
const response = family === "ogc-records"
|
|
89
|
+
? await client.listOgcRecordCollections(request)
|
|
90
|
+
: await client.listOgcCollections(request);
|
|
91
|
+
return {
|
|
92
|
+
available: true,
|
|
93
|
+
sources: (response.collections ?? []).map((collection) => ({
|
|
94
|
+
source: `${family}:${collection.id}`,
|
|
95
|
+
protocol: family,
|
|
96
|
+
title: collection.title ?? collection.id,
|
|
97
|
+
capabilities: capabilitiesFor(family),
|
|
98
|
+
})),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return {
|
|
103
|
+
available: false,
|
|
104
|
+
reason: `no ${family} collections on this target: ${err instanceof Error ? err.message : String(err)}`,
|
|
105
|
+
sources: [],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export async function execute(client, input) {
|
|
110
|
+
return withCapabilityHonesty(async () => {
|
|
111
|
+
const families = {};
|
|
112
|
+
if (input.protocol === "auto" || input.protocol === "geoservices") {
|
|
113
|
+
families.geoservices = await discoverGeoServices(client, input.maxServices);
|
|
114
|
+
}
|
|
115
|
+
if (input.protocol === "auto" || input.protocol === "ogc-features") {
|
|
116
|
+
families["ogc-features"] = await discoverOgc(client, "ogc-features", input.layout);
|
|
117
|
+
}
|
|
118
|
+
if (input.protocol === "ogc-records") {
|
|
119
|
+
families["ogc-records"] = await discoverOgc(client, "ogc-records", input.layout);
|
|
120
|
+
}
|
|
121
|
+
const sources = Object.values(families).flatMap((family) => family.sources);
|
|
122
|
+
return jsonText({
|
|
123
|
+
sources,
|
|
124
|
+
sourceCount: sources.length,
|
|
125
|
+
families: Object.fromEntries(Object.entries(families).map(([name, outcome]) => [
|
|
126
|
+
name,
|
|
127
|
+
{
|
|
128
|
+
available: outcome.available,
|
|
129
|
+
...(outcome.reason ? { reason: outcome.reason } : {}),
|
|
130
|
+
count: outcome.sources.length,
|
|
131
|
+
},
|
|
132
|
+
])),
|
|
133
|
+
guidance: sources.length > 0
|
|
134
|
+
? "Pass a `source` value verbatim to honua_describe_layer / honua_query_features / honua_count_features / honua_get_extent / honua_statistics."
|
|
135
|
+
: 'No source catalog is published here. Address a known source directly, e.g. source="ogc-features:<collectionId>", "stac:<collectionId>", "wfs:<typeName>", "odata:<entitySet>", or "geoservices-feature-service:<serviceId>/<layerId>".',
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -1,41 +1,114 @@
|
|
|
1
1
|
import type { HonuaClient } from "@honua/sdk-js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* `honua_query_features` — protocol-neutral feature read (#1005).
|
|
5
|
+
*
|
|
6
|
+
* Addresses a source by its neutral `<protocol>:<address>` reference, filters
|
|
7
|
+
* with the typed semantic filter / GeoJSON geometry / canonical temporal
|
|
8
|
+
* predicate, and executes through the SDK's canonical `Source.query()`, so the
|
|
9
|
+
* same call means the same thing against GeoServices, OGC API Features, STAC,
|
|
10
|
+
* WFS, and OData. The deprecated `serviceId` + `layerId` pair is still accepted.
|
|
11
|
+
*/
|
|
3
12
|
export declare const schema: z.ZodObject<{
|
|
4
|
-
serviceId: z.ZodString;
|
|
5
|
-
layerId: z.ZodNumber;
|
|
6
|
-
where: z.ZodOptional<z.ZodString>;
|
|
7
13
|
outFields: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
orderBy: z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodObject<{
|
|
15
|
+
field: z.ZodString;
|
|
16
|
+
direction: z.ZodOptional<z.ZodEnum<["asc", "desc"]>>;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
field: string;
|
|
19
|
+
direction?: "asc" | "desc" | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
field: string;
|
|
22
|
+
direction?: "asc" | "desc" | undefined;
|
|
23
|
+
}>, "many">, z.ZodString]>>;
|
|
12
24
|
limit: z.ZodOptional<z.ZodNumber>;
|
|
13
25
|
offset: z.ZodOptional<z.ZodNumber>;
|
|
14
26
|
returnGeometry: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
27
|
+
geometryFormat: z.ZodOptional<z.ZodEnum<["geojson", "esri-json"]>>;
|
|
28
|
+
outSr: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
29
|
+
filter: z.ZodOptional<z.ZodType<import("../neutral/filter.js").FilterNode, z.ZodTypeDef, import("../neutral/filter.js").FilterNode>>;
|
|
30
|
+
where: z.ZodOptional<z.ZodString>;
|
|
31
|
+
bbox: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
32
|
+
bboxSrid: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
geometry: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
34
|
+
geometryType: z.ZodOptional<z.ZodEnum<["esriGeometryPoint", "esriGeometryPolyline", "esriGeometryPolygon", "esriGeometryEnvelope", "esriGeometryMultipoint"]>>;
|
|
35
|
+
spatialRel: z.ZodOptional<z.ZodEnum<["intersects", "contains", "within", "crosses", "touches", "overlaps", "bbox-intersects"]>>;
|
|
36
|
+
temporal: z.ZodOptional<z.ZodObject<{
|
|
37
|
+
instant: z.ZodOptional<z.ZodString>;
|
|
38
|
+
start: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
39
|
+
end: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
40
|
+
field: z.ZodOptional<z.ZodString>;
|
|
41
|
+
}, "strip", z.ZodTypeAny, {
|
|
42
|
+
field?: string | undefined;
|
|
43
|
+
instant?: string | undefined;
|
|
44
|
+
start?: string | null | undefined;
|
|
45
|
+
end?: string | null | undefined;
|
|
46
|
+
}, {
|
|
47
|
+
field?: string | undefined;
|
|
48
|
+
instant?: string | undefined;
|
|
49
|
+
start?: string | null | undefined;
|
|
50
|
+
end?: string | null | undefined;
|
|
51
|
+
}>>;
|
|
52
|
+
source: z.ZodOptional<z.ZodString>;
|
|
53
|
+
layout: z.ZodOptional<z.ZodEnum<["honua-facade", "ogc-api", "auto", "stac-api", "stac-static"]>>;
|
|
54
|
+
serviceId: z.ZodOptional<z.ZodString>;
|
|
55
|
+
layerId: z.ZodOptional<z.ZodNumber>;
|
|
15
56
|
}, "strip", z.ZodTypeAny, {
|
|
16
|
-
serviceId: string;
|
|
17
|
-
layerId: number;
|
|
18
57
|
returnGeometry: boolean;
|
|
19
|
-
|
|
58
|
+
filter?: import("../neutral/filter.js").FilterNode | undefined;
|
|
59
|
+
serviceId?: string | undefined;
|
|
20
60
|
geometry?: Record<string, unknown> | undefined;
|
|
61
|
+
bbox?: number[] | undefined;
|
|
21
62
|
geometryType?: "esriGeometryPoint" | "esriGeometryPolyline" | "esriGeometryPolygon" | "esriGeometryEnvelope" | "esriGeometryMultipoint" | undefined;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
63
|
+
temporal?: {
|
|
64
|
+
field?: string | undefined;
|
|
65
|
+
instant?: string | undefined;
|
|
66
|
+
start?: string | null | undefined;
|
|
67
|
+
end?: string | null | undefined;
|
|
68
|
+
} | undefined;
|
|
69
|
+
layout?: "honua-facade" | "ogc-api" | "auto" | "stac-api" | "stac-static" | undefined;
|
|
70
|
+
layerId?: number | undefined;
|
|
71
|
+
source?: string | undefined;
|
|
72
|
+
orderBy?: string | {
|
|
73
|
+
field: string;
|
|
74
|
+
direction?: "asc" | "desc" | undefined;
|
|
75
|
+
}[] | undefined;
|
|
76
|
+
where?: string | undefined;
|
|
77
|
+
bboxSrid?: number | undefined;
|
|
78
|
+
spatialRel?: "intersects" | "contains" | "within" | "crosses" | "touches" | "overlaps" | "bbox-intersects" | undefined;
|
|
25
79
|
limit?: number | undefined;
|
|
80
|
+
outFields?: string[] | undefined;
|
|
26
81
|
offset?: number | undefined;
|
|
82
|
+
geometryFormat?: "geojson" | "esri-json" | undefined;
|
|
83
|
+
outSr?: string | number | undefined;
|
|
27
84
|
}, {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
where?: string | undefined;
|
|
85
|
+
filter?: import("../neutral/filter.js").FilterNode | undefined;
|
|
86
|
+
serviceId?: string | undefined;
|
|
31
87
|
geometry?: Record<string, unknown> | undefined;
|
|
88
|
+
bbox?: number[] | undefined;
|
|
32
89
|
geometryType?: "esriGeometryPoint" | "esriGeometryPolyline" | "esriGeometryPolygon" | "esriGeometryEnvelope" | "esriGeometryMultipoint" | undefined;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
90
|
+
temporal?: {
|
|
91
|
+
field?: string | undefined;
|
|
92
|
+
instant?: string | undefined;
|
|
93
|
+
start?: string | null | undefined;
|
|
94
|
+
end?: string | null | undefined;
|
|
95
|
+
} | undefined;
|
|
96
|
+
layout?: "honua-facade" | "ogc-api" | "auto" | "stac-api" | "stac-static" | undefined;
|
|
97
|
+
layerId?: number | undefined;
|
|
98
|
+
source?: string | undefined;
|
|
99
|
+
orderBy?: string | {
|
|
100
|
+
field: string;
|
|
101
|
+
direction?: "asc" | "desc" | undefined;
|
|
102
|
+
}[] | undefined;
|
|
103
|
+
where?: string | undefined;
|
|
104
|
+
bboxSrid?: number | undefined;
|
|
105
|
+
spatialRel?: "intersects" | "contains" | "within" | "crosses" | "touches" | "overlaps" | "bbox-intersects" | undefined;
|
|
36
106
|
limit?: number | undefined;
|
|
107
|
+
outFields?: string[] | undefined;
|
|
37
108
|
offset?: number | undefined;
|
|
38
109
|
returnGeometry?: boolean | undefined;
|
|
110
|
+
geometryFormat?: "geojson" | "esri-json" | undefined;
|
|
111
|
+
outSr?: string | number | undefined;
|
|
39
112
|
}>;
|
|
40
113
|
export type Input = z.infer<typeof schema>;
|
|
41
114
|
export declare function execute(client: HonuaClient, input: Input): Promise<{
|
|
@@ -43,5 +116,12 @@ export declare function execute(client: HonuaClient, input: Input): Promise<{
|
|
|
43
116
|
type: "text";
|
|
44
117
|
text: string;
|
|
45
118
|
}>;
|
|
119
|
+
} | {
|
|
120
|
+
structuredContent: Record<string, unknown>;
|
|
121
|
+
isError: true;
|
|
122
|
+
content: Array<{
|
|
123
|
+
type: "text";
|
|
124
|
+
text: string;
|
|
125
|
+
}>;
|
|
46
126
|
}>;
|
|
47
127
|
//# sourceMappingURL=query-features.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-features.d.ts","sourceRoot":"","sources":["../../../src/tools/query-features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"query-features.d.ts","sourceRoot":"","sources":["../../../src/tools/query-features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB;;;;;;;;GAQG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE3C,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;;;;;;;;GAyB9D"}
|