@honua/mcp-server
v0.1.0-beta.0
Published
MCP server for Honua geospatial feature services
Readme
@honua/mcp-server
The platform-free Model Context Protocol (MCP) server for geospatial feature services. Point it at any public Esri FeatureServer or OGC API endpoint and it exposes discovery, query, and analysis workflows to any MCP client — with zero platform lock-in and no metering. Mapbox, CARTO, and Esri each ship an MCP server bound to their own platform; this one is bound to none.
Release status: beta. Tool contracts are certified against live and fixture targets on every release; remaining pre-1.0 work is hardening, not surface change.
Two modes:
- Standalone (platform-free) — the front door. The
honua-mcpbin runs the direct-SDK surface against any public FeatureServer/OGC endpoint. No Honua server, no admin API, no/mcpcatalog required. - Honua-enhanced — the upgrade path. The
honua-mcp-proxybin bridges a Honua deployment's full/mcpoperator catalog (planning, async jobs, publishing) to stdio. Honua does not expose an AI/MCP feature-mutation tool — AI operational data editing is not supported (honua-server ADR-0028).
Requirements
- Node.js
>=20 - Any reachable FeatureServer/OGC endpoint (public or Honua)
Platform-free mode (any ArcGIS / OGC endpoint)
Point HONUA_BASE_URL at any origin/folder that serves the standard GeoServices
REST paths (/rest/services, /FeatureServer/{id}/query). Example — the public
US Census 2020 apportionment FeatureServer on services.arcgis.com:
npm install
npm run build
HONUA_BASE_URL="https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis" \
HONUA_TRANSPORT="rest" node dist/src/index.jsTools that require a Honua-only surface (server-side styling via OGC API – Styles,
a /rest/services catalog) degrade gracefully on a plain endpoint: they
return a structured result
{ "available": false, "surface": "OGC API - Styles", "reason": "…", "guidance": "…" }instead of crashing, hanging, or returning misleading empty data. This is the same skip-with-reason honesty the certification suite uses.
Environment Variables
HONUA_BASE_URL(required): absolute base URL — a public ArcGIS folder (https://services.arcgis.com/<org>/arcgis) or a Honua deployment (https://honua.example.com).HONUA_TRANSPORT(optional):grpc-web(default, Honua deployments) orrest. Userestfor plain public ArcGIS/OGC endpoints.HONUA_API_KEY(optional): API key when your deployment requires it. Public endpoints need none.HONUA_TIMEOUT_MS(optional): request timeout in milliseconds (default30000)HONUA_RETRY_MAX_RETRIES(optional): retry attempts for transient failures (default2)
When HONUA_API_KEY is configured, use https:// for non-localhost servers.
MCP Tools
All read-only:
honua_list_services— discover services (degrades if the target has no catalog)honua_describe_layerhonua_query_featureshonua_count_featureshonua_get_extenthonua_statisticshonua_explain_capability_gaphonua_get_style,honua_apply_style_preset— structured-unavailable on a plain FeatureServer
MCP Resources
honua://serviceshonua://services/{encodedServiceId}/layers/{layerId}honua://styles,honua://styles/{styleId}— structured-unavailable on a plain FeatureServer
Certification
The package ships a deterministic MCP certification harness that proves the
advertised MCP surface is well-formed and conformant to the open
geospatial-mcp standard. It is
fully offline — no model/API calls, no network in the default path — and is the
evidence document for the WS-H "Provability" workstream.
For each tool the server advertises (over an in-memory MCP transport) it:
- Enumerates
tools/list,resources/list, andprompts/list. - Validates each
inputSchema(and anystructuredContentoutput schema) is well-formed JSON Schema, accepting both the draft-07 dialect emitted by zod-to-json-schema and the draft 2020-12 dialect of the standard. - Where a vendored standard schema matches the advertised tool (by the
standard's
referenceToolName), checks conformance — every standardrequiredproperty must be accepted with a compatible type. Standard tools that are not advertised, and advertised tools outside the standard, are recorded as known gaps, not failures. - Round-trips every read-only tool (
tools/callwith a fixture input), validating the response. Write/destructive tools are never called.
It emits a stable machine-readable JSON report plus a human-readable Markdown summary, and exits non-zero on any conformance/round-trip failure.
# Run the certifier against the offline fixture backend and write artifacts:
npm run certify
# CI entry points (also runnable locally):
npm run test:certification # gate: runs harness tests + certifier, exits non-zero on failure
npm run test:certification:artifact # evidence: writes artifacts, always exits 0Platform-free certification lane
A dedicated standalone target (HONUA_MCP_CERT_TARGET=standalone, or
--target standalone) certifies the platform-free surface against an in-process
fixture of a plain public FeatureServer — the recorded US Census 2020
apportionment layer from services.arcgis.com, with no Honua surfaces. It
proves the tools certify green with honest skips against a non-Honua endpoint:
the data tools round-trip against real recorded data, the Honua-only style tools
degrade to structured "not available" results, and the auth/mutation/job contracts
skip-with-reason. Fixture-backed and deterministic — no network.
npm run certify:standalone # platform-free cert (plain FeatureServer fixture)
npm run test:certification:standalone # CI gate variantThe fixture is recorded by scripts/record-census-fixtures.mjs into
src/certification/census-data.ts; the evaluator that replays it is verified for
parity against the live recordings in test/certification/census-fixture-client.test.ts.
Artifacts are written to the package root as
mcp-certification-results.json and mcp-certification-results.md (gitignored;
uploaded by CI). To certify against a live honua-server, set HONUA_BASE_URL
(and HONUA_TRANSPORT, HONUA_MCP_SERVICE_ID, HONUA_MCP_LAYER_ID); the
harness then drives a real HonuaClient instead of the fixture.
The standard schemas are vendored under
certification/geospatial-mcp-schemas/ (see that directory's PROVENANCE.md
for the pinned source revision).
Transport-symmetric stdio proxy
The honua server exposes one MCP catalog over streamable-HTTP/SSE at /mcp.
Claude-Desktop-style clients speak stdio. Rather than reimplement that
catalog (which is how the HTTP and stdio surfaces historically drifted apart),
this package ships a stdio proxy (honua-mcp-proxy) that bridges a local
stdio MCP client to the remote HTTP-SSE MCP server. It connects upstream as an
MCP client and re-exposes the same catalog downstream over stdio — identical
tools, identical input/output schemas, identical resources and prompts, and live
tools/list_changed notifications. There is one source-of-truth catalog (the
server's /mcp); the SDK proxies it, so the two transports are symmetric by
construction. (Cross-repo: honua-io/honua-server#1950.)
# Bridge a stdio MCP client to a remote honua /mcp surface:
HONUA_MCP_REMOTE_URL="https://demo.honua.io/mcp" honua-mcp-proxyEnvironment variables:
HONUA_MCP_REMOTE_URL(required; aliasHONUA_MCP_URL): the remote honua/mcpendpoint to proxy.HONUA_MCP_AUTH_TOKEN(optional): sent asAuthorization: Bearer <token>.HONUA_API_KEY(optional): sent asx-api-key.
A parity test (test/proxy.test.ts) asserts the tool/resource/template catalog
the downstream client sees is byte-identical to the upstream surface, that
tools/call and resource reads round-trip identically, and that list_changed
notifications are forwarded.
Cross-model workflow eval (provability)
The package ships a cross-model workflow eval that proves the "any client →
any workflow" claim: a held-out corpus of GIS workflows (src/eval/corpus.ts)
is driven through the MCP surface by different client LLMs and graded for
end-to-end success / clarification / edit rates per model. (Cross-repo:
honua-io/honua-server#1956.)
- Deterministic control (offline, CI): a scripted "ideal client" runs every
workflow's real
tools/callround-trips against the offline fixture surface — no model/API calls — and is graded identically to the live models. This is the reproducible CI gate. - Live cross-model (Claude + GPT): when
ANTHROPIC_API_KEY/OPENAI_API_KEYare set, the Claude driver (latest Opus,claude-opus-4-8) and the GPT driver (GA flagship,gpt-5.5, override withOPENAI_MODEL) run the corpus through a real agentic tool-use loop over the identical catalog. The@anthropic-ai/sdk/openaipackages are imported dynamically (not dependencies); keys come from the environment and are never hardcoded. SetHONUA_MCP_REMOTE_URLto drive a live remote/mcpinstead of the fixture.
npm run eval # run the eval (live models join if their keys are set)
npm run eval:offline # force the deterministic control + fixture surface
npm run test:eval # gate: harness tests + offline eval, exits non-zero on failure
npm run test:eval:artifact # evidence: writes artifacts, always exits 0Artifacts (mcp-eval-results.json / mcp-eval-results.md, gitignored, uploaded
by CI) record the per-model scorecard. The CI gate asserts the deterministic
control passes every scenario; live cross-model runs are recorded but
informational.
Platform-free semantic corpus (src/eval/standalone-corpus.ts)
The standalone corpus is 50+ scenarios run against the plain public
FeatureServer fixture (the census layer) with semantic grading — not just tool
trajectory. Each scenario asserts the meaning of the answer: correct feature
counts (52 rows, 4 states with ≥20 seats), correct geographic facts (California is
the most populous; Wyoming the least; the House totals 435 seats), correct tool
selection for ambiguous asks (count vs. query vs. statistics), refusal /
clarification behavior on ambiguous or unsupported requests, and anti-hallucination
guards. Because the fixture replays real recorded data, a wrong number or a
hallucinated place name fails. The grading taxonomy is documented in
evals/README.md.
npm run eval:standalone # deterministic control over the census fixture (offline)Live lane (paid, manual only)
The operator corpus (src/eval/operator-corpus.ts, 8 harder scenarios) is
meant to run against a live honua-server operator /mcp surface with real
models. This is a billable lane: it makes real Anthropic / OpenAI (or AWS
Bedrock) calls. It never runs on push/PR — locally via npm run eval:live, or in
CI via the manual MCP Live Cross-Model Eval workflow
(.github/workflows/mcp-eval-live.yml, workflow_dispatch-only). The live model
SDKs are not package dependencies; install them first for a live run:
npm install --no-save @anthropic-ai/sdk openai # only needed for live runseval:live runs the operator corpus (--corpus operator) against the remote
/mcp and always writes artifacts (--artifact-only). Authentication uses the
same headers as the stdio proxy — no dev-auth bypass; the resolved auth mode
(bearer / api-key / anonymous) is recorded in the artifact so the run
proves it was authenticated. Set HONUA_EVAL_REQUIRE_AUTH=1 to refuse an
anonymous run outright.
Shared env for every live run:
HONUA_MCP_REMOTE_URL(required): the operator/mcpendpoint, e.g.https://demo.honua.io/mcp.HONUA_MCP_AUTH_TOKEN: sent asAuthorization: Bearer <token>(preferred; ⇒ auth modebearer).HONUA_API_KEY: sent asx-api-key(⇒ auth modeapi-key) when the deployment uses key auth instead.HONUA_EVAL_REQUIRE_AUTH=1(recommended): fail fast if neither credential is present.
# Anthropic Claude (default claude-opus-4-8; override with HONUA_EVAL_ANTHROPIC_MODEL):
HONUA_MCP_REMOTE_URL="https://demo.honua.io/mcp" \
HONUA_MCP_AUTH_TOKEN="$HONUA_TOKEN" \
HONUA_EVAL_REQUIRE_AUTH=1 \
ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
npm run eval:live -- --driver anthropic
# OpenAI GPT (default gpt-5.5; override with OPENAI_MODEL, e.g. gpt-5.6-sol once you have access):
HONUA_MCP_REMOTE_URL="https://demo.honua.io/mcp" \
HONUA_MCP_AUTH_TOKEN="$HONUA_TOKEN" \
HONUA_EVAL_REQUIRE_AUTH=1 \
OPENAI_API_KEY="$OPENAI_API_KEY" \
npm run eval:live -- --driver openai
# Claude via Amazon Bedrock (AWS credential chain; default Sonnet 4.5,
# override with HONUA_EVAL_BEDROCK_MODEL — most ids need a us.* inference profile):
HONUA_MCP_REMOTE_URL="https://demo.honua.io/mcp" \
HONUA_MCP_AUTH_TOKEN="$HONUA_TOKEN" \
HONUA_EVAL_REQUIRE_AUTH=1 \
HONUA_EVAL_BEDROCK=1 AWS_REGION=us-west-2 \
HONUA_EVAL_BEDROCK_MODEL="us.anthropic.claude-sonnet-4-5-20250929-v1:0" \
npm run eval:live -- --driver bedrockPass multiple drivers to compare them in one artifact:
npm run eval:live -- --driver anthropic,openai. Every driver is graded against
the identical operator corpus and catalog, and the artifact's
catalog.unresolvedRequiredTools names any required tool the live surface did
not advertise — so a scenario that fails does so for a real capability gap, not a
silent tool name-resolution bug (the runner resolves required tools against the
live tools/list, never against the vendored certification index).
