@honua/mcp-server 0.0.20-alpha.0 → 0.1.1-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/README.md +141 -15
- package/certification/geospatial-mcp-schemas/PROVENANCE.md +15 -7
- package/certification/geospatial-mcp-schemas/conformance/manifest.schema.json +6 -0
- package/certification/geospatial-mcp-schemas/index.json +88 -9
- package/certification/geospatial-mcp-schemas/tools/apply_style_preset.schema.json +13 -9
- package/certification/geospatial-mcp-schemas/tools/buffer_features.schema.json +60 -0
- package/certification/geospatial-mcp-schemas/tools/edit_features.schema.json +74 -0
- package/certification/geospatial-mcp-schemas/tools/export_dataset.schema.json +60 -0
- package/certification/geospatial-mcp-schemas/tools/geocode_addresses.schema.json +34 -0
- package/certification/geospatial-mcp-schemas/tools/get_style.schema.json +13 -3
- package/certification/geospatial-mcp-schemas/tools/ingest_dataset.schema.json +45 -0
- package/certification/geospatial-mcp-schemas/tools/join_features.schema.json +73 -0
- package/certification/geospatial-mcp-schemas/tools/overlay_features.schema.json +53 -0
- package/certification/geospatial-mcp-schemas/tools/query_features.schema.json +20 -0
- package/certification/geospatial-mcp-schemas/tools/render_map.schema.json +5 -0
- package/certification/geospatial-mcp-schemas/tools/reproject_features.schema.json +49 -0
- package/certification/geospatial-mcp-schemas/tools/summarize_statistics.schema.json +71 -0
- package/dist/src/agent-execution.d.ts +16 -0
- package/dist/src/agent-execution.d.ts.map +1 -0
- package/dist/src/agent-execution.js +46 -0
- package/dist/src/capability.d.ts +48 -0
- package/dist/src/capability.d.ts.map +1 -0
- package/dist/src/capability.js +44 -0
- package/dist/src/certification/census-data.d.ts +33 -0
- package/dist/src/certification/census-data.d.ts.map +1 -0
- package/dist/src/certification/census-data.js +506 -0
- package/dist/src/certification/census-fixture-client.d.ts +7 -0
- package/dist/src/certification/census-fixture-client.d.ts.map +1 -0
- package/dist/src/certification/census-fixture-client.js +226 -0
- package/dist/src/certification/certifier.d.ts +7 -1
- package/dist/src/certification/certifier.d.ts.map +1 -1
- package/dist/src/certification/certifier.js +52 -7
- package/dist/src/certification/cli.js +19 -4
- package/dist/src/certification/contracts.d.ts +41 -0
- package/dist/src/certification/contracts.d.ts.map +1 -1
- package/dist/src/certification/contracts.js +71 -0
- package/dist/src/certification/fixture-client.d.ts.map +1 -1
- package/dist/src/certification/fixtures.d.ts +13 -0
- package/dist/src/certification/fixtures.d.ts.map +1 -1
- package/dist/src/certification/fixtures.js +28 -0
- package/dist/src/certification/json-schema.d.ts +23 -1
- package/dist/src/certification/json-schema.d.ts.map +1 -1
- package/dist/src/certification/json-schema.js +10 -2
- package/dist/src/certification/lifecycle.d.ts +14 -0
- package/dist/src/certification/lifecycle.d.ts.map +1 -0
- package/dist/src/certification/lifecycle.js +326 -0
- package/dist/src/certification/operator-catalog.d.ts +8 -0
- package/dist/src/certification/operator-catalog.d.ts.map +1 -1
- package/dist/src/certification/operator-catalog.js +189 -5
- package/dist/src/certification/report.d.ts.map +1 -1
- package/dist/src/certification/report.js +13 -0
- package/dist/src/certification/run.d.ts.map +1 -1
- package/dist/src/certification/run.js +1 -0
- package/dist/src/certification/schema-index.d.ts +25 -0
- package/dist/src/certification/schema-index.d.ts.map +1 -1
- package/dist/src/certification/schema-index.js +27 -0
- package/dist/src/certification/target.d.ts +9 -1
- package/dist/src/certification/target.d.ts.map +1 -1
- package/dist/src/certification/target.js +54 -2
- package/dist/src/eval/cli.js +4 -2
- 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 +16 -0
- package/dist/src/eval/drivers/deterministic.d.ts.map +1 -1
- package/dist/src/eval/drivers/deterministic.js +13 -0
- package/dist/src/eval/grade.d.ts.map +1 -1
- package/dist/src/eval/grade.js +20 -1
- package/dist/src/eval/report.d.ts +5 -0
- package/dist/src/eval/report.d.ts.map +1 -1
- package/dist/src/eval/report.js +3 -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/eval/standalone-corpus.d.ts +3 -0
- package/dist/src/eval/standalone-corpus.d.ts.map +1 -0
- package/dist/src/eval/standalone-corpus.js +699 -0
- package/dist/src/eval/types.d.ts +25 -0
- package/dist/src/eval/types.d.ts.map +1 -1
- package/dist/src/helpers.d.ts +1 -1
- package/dist/src/helpers.d.ts.map +1 -1
- package/dist/src/index.d.ts +37 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +47 -22
- package/dist/src/nl-map-control.d.ts +70 -0
- package/dist/src/nl-map-control.d.ts.map +1 -0
- package/dist/src/nl-map-control.js +470 -0
- package/dist/src/provenance.d.ts +44 -0
- package/dist/src/provenance.d.ts.map +1 -0
- package/dist/src/provenance.js +37 -0
- package/dist/src/resources/styles.d.ts.map +1 -1
- package/dist/src/resources/styles.js +36 -3
- package/dist/src/stable-json.d.ts +14 -0
- package/dist/src/stable-json.d.ts.map +1 -0
- package/dist/src/stable-json.js +126 -0
- package/dist/src/styles.d.ts +2 -0
- package/dist/src/styles.d.ts.map +1 -1
- package/dist/src/styles.js +29 -3
- package/dist/src/tools/apply-style-preset.d.ts.map +1 -1
- package/dist/src/tools/apply-style-preset.js +14 -2
- package/dist/src/tools/explain-capability-gap.d.ts +3 -3
- package/dist/src/tools/explain-capability-gap.d.ts.map +1 -1
- package/dist/src/tools/explain-capability-gap.js +1 -1
- package/dist/src/tools/get-style.d.ts.map +1 -1
- package/dist/src/tools/get-style.js +24 -13
- package/dist/src/tools/list-services.d.ts.map +1 -1
- package/dist/src/tools/list-services.js +16 -1
- package/package.json +27 -2
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const MAX_NODES = 8_192;
|
|
2
|
+
const MAX_DEPTH = 32;
|
|
3
|
+
const MAX_BYTES = 1_048_576;
|
|
4
|
+
const MAX_OBJECT_PROPERTIES = 128;
|
|
5
|
+
const MAX_ARRAY_LENGTH = 1_024;
|
|
6
|
+
const MAX_STRING_CODE_UNITS = 65_536;
|
|
7
|
+
const SNAPSHOT_ERRORS = new WeakSet();
|
|
8
|
+
/** Stable boundary error whose message never includes a reflected value or trap error. */
|
|
9
|
+
export class McpJsonSnapshotError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "McpJsonSnapshotError";
|
|
13
|
+
SNAPSHOT_ERRORS.add(this);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detach untrusted JSON without invoking property getters.
|
|
18
|
+
*
|
|
19
|
+
* The clone is deeply frozen and bounded before any asynchronous authorization
|
|
20
|
+
* callback can observe it. Reflection failures (including Proxy traps) collapse
|
|
21
|
+
* to one stable error instead of reflecting attacker-controlled messages.
|
|
22
|
+
*/
|
|
23
|
+
export function snapshotMcpJson(input, label) {
|
|
24
|
+
try {
|
|
25
|
+
return snapshot(input, 0, new WeakSet(), { nodes: 0, bytes: 0 });
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error !== null && typeof error === "object" && SNAPSHOT_ERRORS.has(error))
|
|
29
|
+
throw error;
|
|
30
|
+
throw new McpJsonSnapshotError(`${label} could not be safely snapshotted`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function snapshot(value, depth, ancestors, budget) {
|
|
34
|
+
budget.nodes += 1;
|
|
35
|
+
if (budget.nodes > MAX_NODES)
|
|
36
|
+
invalid("MCP JSON exceeds the node limit");
|
|
37
|
+
if (depth > MAX_DEPTH)
|
|
38
|
+
invalid("MCP JSON exceeds the depth limit");
|
|
39
|
+
addBytes(budget, 8);
|
|
40
|
+
if (value === null || typeof value === "boolean")
|
|
41
|
+
return value;
|
|
42
|
+
if (typeof value === "string") {
|
|
43
|
+
if (value.length > MAX_STRING_CODE_UNITS)
|
|
44
|
+
invalid("MCP JSON contains an oversized string");
|
|
45
|
+
addBytes(budget, utf8Bytes(value));
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
if (typeof value === "number") {
|
|
49
|
+
if (!Number.isFinite(value))
|
|
50
|
+
invalid("MCP JSON contains a non-finite number");
|
|
51
|
+
return Object.is(value, -0) ? 0 : value;
|
|
52
|
+
}
|
|
53
|
+
if (typeof value !== "object")
|
|
54
|
+
invalid("MCP JSON contains an unsupported value");
|
|
55
|
+
if (ancestors.has(value))
|
|
56
|
+
invalid("MCP JSON must not contain cycles");
|
|
57
|
+
ancestors.add(value);
|
|
58
|
+
const result = Array.isArray(value)
|
|
59
|
+
? snapshotArray(value, depth, ancestors, budget)
|
|
60
|
+
: snapshotObject(value, depth, ancestors, budget);
|
|
61
|
+
ancestors.delete(value);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
function snapshotArray(input, depth, ancestors, budget) {
|
|
65
|
+
if (Object.getPrototypeOf(input) !== Array.prototype)
|
|
66
|
+
invalid("MCP JSON arrays must use the standard prototype");
|
|
67
|
+
const lengthDescriptor = Reflect.getOwnPropertyDescriptor(input, "length");
|
|
68
|
+
const length = lengthDescriptor && "value" in lengthDescriptor ? lengthDescriptor.value : undefined;
|
|
69
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > MAX_ARRAY_LENGTH) {
|
|
70
|
+
invalid("MCP JSON contains an invalid or oversized array");
|
|
71
|
+
}
|
|
72
|
+
const keys = Reflect.ownKeys(input);
|
|
73
|
+
if (keys.some((key) => typeof key !== "string"))
|
|
74
|
+
invalid("MCP JSON must not contain symbol keys");
|
|
75
|
+
if (keys.length !== length + 1 || !keys.includes("length")) {
|
|
76
|
+
invalid("MCP JSON arrays must be dense and must not contain extra properties");
|
|
77
|
+
}
|
|
78
|
+
const output = [];
|
|
79
|
+
for (let index = 0; index < length; index += 1) {
|
|
80
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(input, String(index));
|
|
81
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
82
|
+
invalid("MCP JSON arrays must contain enumerable data properties");
|
|
83
|
+
}
|
|
84
|
+
output.push(snapshot(descriptor.value, depth + 1, ancestors, budget));
|
|
85
|
+
}
|
|
86
|
+
return Object.freeze(output);
|
|
87
|
+
}
|
|
88
|
+
function snapshotObject(input, depth, ancestors, budget) {
|
|
89
|
+
const prototype = Object.getPrototypeOf(input);
|
|
90
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
91
|
+
invalid("MCP JSON values must be plain objects");
|
|
92
|
+
const keys = Reflect.ownKeys(input);
|
|
93
|
+
if (keys.length > MAX_OBJECT_PROPERTIES)
|
|
94
|
+
invalid("MCP JSON object exceeds the property limit");
|
|
95
|
+
if (keys.some((key) => typeof key !== "string"))
|
|
96
|
+
invalid("MCP JSON must not contain symbol keys");
|
|
97
|
+
const output = Object.create(null);
|
|
98
|
+
for (const key of keys.sort()) {
|
|
99
|
+
if (key.length > MAX_STRING_CODE_UNITS)
|
|
100
|
+
invalid("MCP JSON contains an oversized property name");
|
|
101
|
+
addBytes(budget, utf8Bytes(key));
|
|
102
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(input, key);
|
|
103
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
104
|
+
invalid("MCP JSON objects must contain enumerable data properties");
|
|
105
|
+
}
|
|
106
|
+
Object.defineProperty(output, key, {
|
|
107
|
+
value: snapshot(descriptor.value, depth + 1, ancestors, budget),
|
|
108
|
+
enumerable: true,
|
|
109
|
+
writable: false,
|
|
110
|
+
configurable: false,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return Object.freeze(output);
|
|
114
|
+
}
|
|
115
|
+
function addBytes(budget, increment) {
|
|
116
|
+
const next = budget.bytes + increment;
|
|
117
|
+
if (!Number.isSafeInteger(next) || next > MAX_BYTES)
|
|
118
|
+
invalid("MCP JSON exceeds the byte limit");
|
|
119
|
+
budget.bytes = next;
|
|
120
|
+
}
|
|
121
|
+
function utf8Bytes(value) {
|
|
122
|
+
return new TextEncoder().encode(value).byteLength;
|
|
123
|
+
}
|
|
124
|
+
function invalid(message) {
|
|
125
|
+
throw new McpJsonSnapshotError(message);
|
|
126
|
+
}
|
package/dist/src/styles.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { HonuaClient } from "@honua/sdk-js";
|
|
2
|
+
/** Human label for the Honua-only styling surface (capability degradation). */
|
|
3
|
+
export declare const STYLE_SURFACE = "OGC API - Styles";
|
|
2
4
|
/**
|
|
3
5
|
* Thin read-only client over the server's OGC API – Styles surface
|
|
4
6
|
* (honua-server, ADR-0048):
|
package/dist/src/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,+EAA+E;AAC/E,eAAO,MAAM,aAAa,qBAAqB,CAAC;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AAEH,qEAAqE;AACrE,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,+EAA+E;AAC/E,eAAO,MAAM,yBAAyB,sCAAsC,CAAC;AAE7E,qCAAqC;AACrC,eAAO,MAAM,iBAAiB,4CAA4C,CAAC;AAE3E,qCAAqC;AACrC,eAAO,MAAM,iBAAiB,4CAA4C,CAAC;AAE3E;;;;GAIG;AACH,eAAO,MAAM,eAAe;;;;CAIlB,CAAC;AAEX,qEAAqE;AACrE,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,eAAe,CAAC;AAE3D,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,0CAA0C;AAC1C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,GAAG,MAAM,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B;AAqCD,mDAAmD;AACnD,wBAAsB,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuB3E;AAED,qEAAqE;AACrE,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGtG;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElG;AASD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4B7F"}
|
package/dist/src/styles.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { CapabilityUnavailableError } from "./capability.js";
|
|
2
|
+
/** Human label for the Honua-only styling surface (capability degradation). */
|
|
3
|
+
export const STYLE_SURFACE = "OGC API - Styles";
|
|
1
4
|
/**
|
|
2
5
|
* Thin read-only client over the server's OGC API – Styles surface
|
|
3
6
|
* (honua-server, ADR-0048):
|
|
@@ -38,8 +41,28 @@ function isRecord(value) {
|
|
|
38
41
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
42
|
}
|
|
40
43
|
async function getJson(client, path, accept) {
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
let response;
|
|
45
|
+
try {
|
|
46
|
+
response = await client.pipelineFetch("GET", path, { headers: { Accept: accept } });
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
// A plain FeatureServer / OGC-Features endpoint has no styling surface, so
|
|
50
|
+
// `GET /ogc/styles*` fails (404, network error, or the SDK's non-2xx throw).
|
|
51
|
+
// Degrade gracefully rather than surfacing a raw crash.
|
|
52
|
+
throw new CapabilityUnavailableError(STYLE_SURFACE, `request to ${path} failed: ${errorMessage(err)}`);
|
|
53
|
+
}
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new CapabilityUnavailableError(STYLE_SURFACE, `${path} returned HTTP ${response.status}`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return (await response.json());
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
throw new CapabilityUnavailableError(STYLE_SURFACE, `${path} did not return JSON (target has no OGC API - Styles surface)`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function errorMessage(err) {
|
|
65
|
+
return err instanceof Error ? err.message : String(err);
|
|
43
66
|
}
|
|
44
67
|
function stylePath(styleId) {
|
|
45
68
|
return `${OGC_STYLES_PATH}/${encodeURIComponent(styleId)}`;
|
|
@@ -48,7 +71,10 @@ function stylePath(styleId) {
|
|
|
48
71
|
export async function listStyles(client) {
|
|
49
72
|
const body = await getJson(client, OGC_STYLES_PATH, "application/json");
|
|
50
73
|
if (!isRecord(body) || !Array.isArray(body.styles)) {
|
|
51
|
-
|
|
74
|
+
// A well-formed styles document always carries a `styles` array (possibly
|
|
75
|
+
// empty). Anything else means the target is not an OGC API - Styles surface;
|
|
76
|
+
// report that honestly instead of returning a misleading empty catalog.
|
|
77
|
+
throw new CapabilityUnavailableError(STYLE_SURFACE, `${OGC_STYLES_PATH} response is not a styles document`);
|
|
52
78
|
}
|
|
53
79
|
const styles = [];
|
|
54
80
|
for (const entry of body.styles) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-style-preset.d.ts","sourceRoot":"","sources":["../../../src/tools/apply-style-preset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"apply-style-preset.d.ts","sourceRoot":"","sources":["../../../src/tools/apply-style-preset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,MAAM;;;;;;EAEjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE3C;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;GAqB9D"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { CapabilityUnavailableError, capabilityUnavailable } from "../capability.js";
|
|
2
3
|
import { jsonText } from "../helpers.js";
|
|
3
|
-
import { resolveStyleRef } from "../styles.js";
|
|
4
|
+
import { STYLE_SURFACE, resolveStyleRef } from "../styles.js";
|
|
5
|
+
const STYLE_GUIDANCE = "This target is a plain FeatureServer/OGC endpoint with no style presets. " +
|
|
6
|
+
"Build a MapLibre style client-side from the layer's fields, or use a Honua deployment for managed presets.";
|
|
4
7
|
export const schema = z.object({
|
|
5
8
|
styleId: z.string().describe("Stable style identifier of the preset to resolve."),
|
|
6
9
|
});
|
|
@@ -18,7 +21,16 @@ export async function execute(client, input) {
|
|
|
18
21
|
// `resolveStyleRef` already fetches the MapLibre stylesheet and inlines it on
|
|
19
22
|
// the `mapbox-style` encoding, so reuse that body instead of issuing a second
|
|
20
23
|
// identical GET /ogc/styles/{id}.
|
|
21
|
-
|
|
24
|
+
let styleRef;
|
|
25
|
+
try {
|
|
26
|
+
styleRef = await resolveStyleRef(client, input.styleId);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
if (err instanceof CapabilityUnavailableError) {
|
|
30
|
+
return capabilityUnavailable(STYLE_SURFACE, err.reason, STYLE_GUIDANCE);
|
|
31
|
+
}
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
22
34
|
const stylesheet = styleRef.encodings.find((e) => e.encoding === "mapbox-style")?.inlineBody ?? null;
|
|
23
35
|
return jsonText({
|
|
24
36
|
style: styleRef,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Capability, Protocol } from "@honua/sdk-js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
export declare const schema: z.ZodObject<{
|
|
4
4
|
capability: z.ZodEffects<z.ZodString, Capability, string>;
|
|
@@ -7,13 +7,13 @@ export declare const schema: z.ZodObject<{
|
|
|
7
7
|
declaredCapabilities: z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodString, Capability, string>, "many">>;
|
|
8
8
|
}, "strip", z.ZodTypeAny, {
|
|
9
9
|
capability: Capability;
|
|
10
|
-
protocol?: Protocol | undefined;
|
|
11
10
|
sourceId?: string | undefined;
|
|
11
|
+
protocol?: Protocol | undefined;
|
|
12
12
|
declaredCapabilities?: Capability[] | undefined;
|
|
13
13
|
}, {
|
|
14
14
|
capability: string;
|
|
15
|
-
protocol?: string | undefined;
|
|
16
15
|
sourceId?: string | undefined;
|
|
16
|
+
protocol?: string | undefined;
|
|
17
17
|
declaredCapabilities?: string[] | undefined;
|
|
18
18
|
}>;
|
|
19
19
|
export type Input = z.infer<typeof schema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain-capability-gap.d.ts","sourceRoot":"","sources":["../../../src/tools/explain-capability-gap.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"explain-capability-gap.d.ts","sourceRoot":"","sources":["../../../src/tools/explain-capability-gap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;EAKjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE3C,wBAAsB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK;;;;;GAI3D"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CAPABILITIES, PROTOCOLS } from "@honua/sdk-js";
|
|
2
1
|
import { explainHonuaCapabilityGap } from "@honua/sdk-js/agent-tools";
|
|
2
|
+
import { CAPABILITIES, PROTOCOLS } from "@honua/sdk-js/contract";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { jsonText } from "../helpers.js";
|
|
5
5
|
const capabilitySchema = z.string().refine((value) => CAPABILITIES.includes(value), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-style.d.ts","sourceRoot":"","sources":["../../../src/tools/get-style.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-style.d.ts","sourceRoot":"","sources":["../../../src/tools/get-style.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,MAAM;;;;;;EAEjB,CAAC;AAEH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE3C;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;;;;;GAsB9D"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { CapabilityUnavailableError, capabilityUnavailable } from "../capability.js";
|
|
2
3
|
import { jsonText } from "../helpers.js";
|
|
3
|
-
import { listStyles, resolveStyleRef } from "../styles.js";
|
|
4
|
+
import { STYLE_SURFACE, listStyles, resolveStyleRef } from "../styles.js";
|
|
5
|
+
const STYLE_GUIDANCE = "This target is a plain FeatureServer/OGC endpoint with no server-side style catalog. " +
|
|
6
|
+
"Query features and build a MapLibre style client-side, or point honua-mcp at a Honua deployment for managed styles.";
|
|
4
7
|
export const schema = z.object({
|
|
5
8
|
styleId: z.string().optional().describe("Stable style identifier. Omit to list the styles available on the server."),
|
|
6
9
|
});
|
|
@@ -12,17 +15,25 @@ export const schema = z.object({
|
|
|
12
15
|
* is available.
|
|
13
16
|
*/
|
|
14
17
|
export async function execute(client, input) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
try {
|
|
19
|
+
if (!input.styleId) {
|
|
20
|
+
const list = await listStyles(client);
|
|
21
|
+
return jsonText({
|
|
22
|
+
styles: list.styles.map((entry) => ({
|
|
23
|
+
styleId: entry.id,
|
|
24
|
+
title: entry.title ?? entry.id,
|
|
25
|
+
uri: `honua://styles/${encodeURIComponent(entry.id)}`,
|
|
26
|
+
})),
|
|
27
|
+
default: list.default ?? null,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const styleRef = await resolveStyleRef(client, input.styleId);
|
|
31
|
+
return jsonText(styleRef);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (err instanceof CapabilityUnavailableError) {
|
|
35
|
+
return capabilityUnavailable(STYLE_SURFACE, err.reason, STYLE_GUIDANCE);
|
|
36
|
+
}
|
|
37
|
+
throw err;
|
|
25
38
|
}
|
|
26
|
-
const styleRef = await resolveStyleRef(client, input.styleId);
|
|
27
|
-
return jsonText(styleRef);
|
|
28
39
|
}
|
|
@@ -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;;;;;
|
|
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"}
|
|
@@ -9,7 +9,22 @@ export const schema = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
const METADATA_CONCURRENCY = 8;
|
|
11
11
|
export async function execute(client, input) {
|
|
12
|
-
|
|
12
|
+
let response;
|
|
13
|
+
try {
|
|
14
|
+
response = await client.listServices();
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
// Some targets expose no service catalog at `/rest/services` — e.g. a base
|
|
18
|
+
// URL pointed straight at a single FeatureServer, or an OGC-only endpoint.
|
|
19
|
+
// Degrade to a structured note instead of crashing: the agent can still
|
|
20
|
+
// describe/query a known service+layer directly.
|
|
21
|
+
return jsonText({
|
|
22
|
+
catalogAvailable: false,
|
|
23
|
+
services: [],
|
|
24
|
+
reason: `service catalog is not available on this target: ${err instanceof Error ? err.message : String(err)}`,
|
|
25
|
+
guidance: "No /rest/services directory here. Call honua_describe_layer / honua_query_features with a known serviceId and layerId, or point the base URL at an ArcGIS folder that lists services.",
|
|
26
|
+
});
|
|
27
|
+
}
|
|
13
28
|
const services = (response.services ?? []).filter((s) => s.type === "FeatureServer");
|
|
14
29
|
if (!input.includeDetails) {
|
|
15
30
|
return jsonText(services.map((s) => ({ serviceId: s.name, type: s.type })));
|
package/package.json
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@honua/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1-beta.0",
|
|
4
4
|
"description": "MCP server for Honua geospatial feature services",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"honua-mcp": "dist/src/index.js",
|
|
8
8
|
"honua-mcp-proxy": "dist/src/proxy.js"
|
|
9
9
|
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/src/index.d.ts",
|
|
13
|
+
"default": "./dist/src/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./agent-execution": {
|
|
16
|
+
"types": "./dist/src/agent-execution.d.ts",
|
|
17
|
+
"default": "./dist/src/agent-execution.js"
|
|
18
|
+
},
|
|
19
|
+
"./nl-map-control": {
|
|
20
|
+
"types": "./dist/src/nl-map-control.d.ts",
|
|
21
|
+
"default": "./dist/src/nl-map-control.js"
|
|
22
|
+
},
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
10
25
|
"scripts": {
|
|
11
26
|
"clean": "rm -rf dist coverage",
|
|
12
27
|
"build": "npm run clean --silent && tsc -p tsconfig.json",
|
|
@@ -16,11 +31,16 @@
|
|
|
16
31
|
"test:unit": "vitest run",
|
|
17
32
|
"test:coverage": "vitest run --coverage",
|
|
18
33
|
"certify": "npm run build --silent && node dist/src/certification/cli.js",
|
|
34
|
+
"certify:standalone": "npm run build --silent && node dist/src/certification/cli.js --target standalone",
|
|
35
|
+
"test:certification:nl-map-control": "vitest run test/certification/nl-map-control.test.ts",
|
|
19
36
|
"test:certification": "npm run build --silent && vitest run test/certification && node dist/src/certification/cli.js",
|
|
20
37
|
"test:certification:artifact": "npm run build --silent && node dist/src/certification/cli.js --artifact-only",
|
|
38
|
+
"test:certification:standalone": "npm run build --silent && node dist/src/certification/cli.js --target standalone",
|
|
21
39
|
"eval": "npm run build --silent && node dist/src/eval/cli.js",
|
|
22
40
|
"eval:offline": "npm run build --silent && node dist/src/eval/cli.js --offline",
|
|
41
|
+
"eval:standalone": "npm run build --silent && node dist/src/eval/cli.js --corpus standalone --offline",
|
|
23
42
|
"eval:live": "npm run build --silent && node dist/src/eval/cli.js --corpus operator --artifact-only",
|
|
43
|
+
"leaderboard": "node scripts/render-leaderboard.mjs",
|
|
24
44
|
"test:eval": "npm run build --silent && vitest run test/eval && node dist/src/eval/cli.js --offline",
|
|
25
45
|
"test:eval:artifact": "npm run build --silent && node dist/src/eval/cli.js --artifact-only",
|
|
26
46
|
"lint": "biome lint src/ test/",
|
|
@@ -40,7 +60,7 @@
|
|
|
40
60
|
"hono": "^4.12.21"
|
|
41
61
|
},
|
|
42
62
|
"peerDependencies": {
|
|
43
|
-
"@honua/sdk-js": "^0.
|
|
63
|
+
"@honua/sdk-js": "^0.1.1-beta.0"
|
|
44
64
|
},
|
|
45
65
|
"devDependencies": {
|
|
46
66
|
"@biomejs/biome": "1.9.4",
|
|
@@ -57,5 +77,10 @@
|
|
|
57
77
|
],
|
|
58
78
|
"engines": {
|
|
59
79
|
"node": ">=20.0.0"
|
|
80
|
+
},
|
|
81
|
+
"repository": {
|
|
82
|
+
"type": "git",
|
|
83
|
+
"url": "git+https://github.com/honua-io/honua-sdk-js.git",
|
|
84
|
+
"directory": "mcp"
|
|
60
85
|
}
|
|
61
86
|
}
|