Skip to main content
Glama
io.github.Unselfisheologism/supercarto

io.github.Unselfisheologism/supercarto

supercarto

mcp-name: io.github.Unselfisheologism/supercarto

skills.sh

LLM-native spatial middleware. Compiles geospatial data into token-budgeted topological graphs that an AI agent can reason over directly.

Give an agent a map without paying the token tax. One file in, both numbers out: examples/synthetic-dense.geojson is 272,993 bytes (~68,000 tokens) raw and compiles at a 1024-token budget to about 890 tokens - 26 nodes (10 named) on 34 edges (streets plus access links), ~99% smaller. Rerun it yourself: supercarto compile examples/synthetic-dense.geojson --budget 1024. Token counts are character-based estimates on a fixed test file; the sun and timestamp lines shift them by a few tokens run to run.

npm install supercarto
pip install supercarto      # Python client, talks MCP over stdio

Give it coordinates

This is the whole product:

import { SuperCarto } from 'supercarto';

const carto = new SuperCarto();

const result = await carto.maplet({
  lat: 35.6833,
  lon: 139.7620,
  radiusM: 400,
  budget: 1500,
});

console.log(result.yaml);

The same file from the headline, compiled below (truncated output; warnings travel inside the map, where an agent reading only the map sees them):

map:
  center: "37.7749, -122.4194"
  source: geojson
  note: Simplified for reasoning; call expand_feature for exact geometry.
nodes:
  n530: {type: poi, name: Bank 0, tags: [bank]}
  n531: {type: poi, name: Cafe 1, tags: [cafe]}
  n673: {type: transit, name: Station 0, tags: [subway_entrance]}
edges:
  n515->n516: {dist: 80m, dir: east, path: road}
  n516->n517: {dist: 80m, dir: east, path: road}
omitted:
  - {layer: building, count: 259}
  - {layer: poi, count: 141}
  - {layer: road, count: 441}
tools:
  - expand_feature(id)

That is about 890 tokens for the whole extract at a 1024 budget: every drop named by layer, nothing silently vanished.


Related MCP server: ThinAir Geo

The problem

You want an agent to know where things are and how to get between them. Three options, all bad:

  • Paste GeoJSON into the prompt. Thousands of tokens per block. The model reasons badly about raw coordinates and will hallucinate them.

  • Call a map API. You get back the same GeoJSON. The token cost is unchanged; only the HTTP round trip differs.

  • Invent a compact wire format and teach the model to read it. A novel grammar in a context window produces hallucinated coordinates and tokens burned inferring the grammar. A model was not trained on your format.

supercarto takes the third option seriously and solves it the only way it can be solved: the model never reads the wire format.

  coordinates          live sources             reasoning format
  35.68, 139.76  ──▶  Overpass / PMTiles  ──▶  topological YAML graph
                                           distances in metres,
                                           compass directions,
                                           built for models

The wire format is a spec you own, optimized for machines. The reasoning format is standard YAML in flow style, using only constructs a model has read billions of times. A deterministic compiler in the middleware does the translation.


An agent works for a person

The person is standing outside. Rain and traffic change whether the trip happens at all, so those are first-class layers here, not an afterthought bolted onto a routing engine.

Weather

No API key. No account. No billing.

const w = await carto.weatherAt(35.6833, 139.7620, 12);

w.now.summary;          // "heavy rain"
w.now.precipitation;    // "rain" | "snow" | "sleet" | "hail" | "drizzle"
w.now.feelsLikeC;       // what they actually feel
$ supercarto weather --lat 35.6833 --lon 139.762
now  clear night, 23.2C (feels 26.9C), wind 4.3km/h, precip none
  2026-10-01T13:00:00Z  22.7C  none      3.5km/h
  2026-10-01T14:00:00Z  22.1C  none      3.1km/h

The MCP tool returns prose rather than fields, because a model repeats "it is raining, take the bus" reliably and re-derives it from twelve numbers unreliably.

When the source is unreachable it returns NaN for every reading and sets degraded, and the tool raises. It does not return zeroes. An agent handed precipitationMm: 0 concludes the weather is dry and sends someone cycling into a storm.

Traffic

const t = await carto.routeWithTraffic({ from, to, mode: 'drive' });

t.freeFlowOnly;   // true when no flow credential is configured
t.worstLevel;     // "severe" - the segment that makes someone late
t.delayS;

Traffic needs a credential, so get_traffic is absent from the tool list until you set one. With no key the routing path reports free-flow and labels it:

$ supercarto traffic --from 37.7749,-122.4194 --to 37.7849,-122.4194
traffic: unknown (no flow source configured)
free-flow estimate: 244s, ignores congestion
note: set TOMTOM_API_KEY or HERE_API_KEY for live conditions

A free-flow estimate for a congested route is worse than no answer, because the person leaves on the schedule the agent gave them. Presenting one as live is the single most damaging thing this library could do, so it does not.

Set TOMTOM_API_KEY or HERE_API_KEY and it becomes live, reporting the worst segment rather than an average.

Air quality

Same keyless contract as weather, one pollutant further:

const a = await carto.airAt(35.6833, 139.7620, 12);

a.now.europeanAqi;      // 62 - the raw index
a.now.pm25UgM3;         // 28.1 - the fraction that sends asthmatics indoors
a.hourly;               // forward-looking window, trimmed at "now"
$ supercarto air --lat 35.6833 --lon 139.762
now  air poor (AQI 62 EU, 65 US), PM2.5 28.1µg/m³, PM10 29.7µg/m³
     gases above good range: NO2 63.5µg/m³
  2026-10-27T08:00:00Z  AQI 74  33.4µg/m³ PM2.5
  2026-10-27T09:00:00Z  AQI 55  21.2µg/m³ PM2.5

The MCP answer names a gas only when it clears its own good bound on the European scale, so a clean day costs four tokens instead of twelve. Every answer carries the distance to the model's sample grid, because a metro with one diesel corridor out of four is not one number. A missing gas reading renders as unknown, never as 0: a zero invented from a gap is how a tool certifies airspace as clean.

Indoor floors

Nobody else publishes this. Google builds indoor maps for its own users and has no reason to hand a third-party agent a clean floor-by-floor graph; Mapbox has nothing comparable; every MCP wrapper returns the same flat GeoJSON.

indoor:
  storeys: 0,1,2
  multi_storey: true
  0: {label: ground, rooms: 12}
    L0n1: {type: corridor}
    L0n2: {type: shop, name: "Blue Bottle"}
    L0n1->L0n2: {dist: 11m}
  v1: {type: lift, levels: [0,1,2], wheelchair: true}
  missing: [1]

Lifts are collapsed across storeys into one vertical link. Rooms only connect to corridors on the same floor — an edge through a concrete slab would send someone through a floor. A room more than 40m from any corridor is left unattached, because a straight line through intervening walls is worse than no edge. Untagged storeys are reported as missing rather than invented.

Transit schedules

Set SUPERCARTO_GTFS to any static GTFS feed (an unzipped directory or a .zip) and get_transit appears: stops, lines, and a service window for the queried day. It is the one agent map tool that answers "can you be somewhere by 9" from an actual schedule, and every agency's failure mode is covered by an honest state rather than a guess:

transit:
  center: "36.913, -116.77"
  radius: 3.0km
  feed: sample-feed
  note: Stop distances are straight-line. Schedule from GTFS feed for 2007-01-11 in America/Los_Angeles.
nodes:
  STAGECOACH: {type: stop, name: "Stagecoach Hotel & Casino", tags: [bus], routes: ["30", "40"], first: 06:00, last: 06:58}
  NADAV: {type: stop, name: "North Ave / D Ave N", tags: [bus], routes: ["40"], first: 06:14, last: 06:44}
edges:
  NADAV->DADAN: {dist: 601m, dir: south, path: bus 40}
  • Three service states, never two. Running today shows routes and first/last departures. A date with nothing running keeps the stops with routes: [] — no transit is not no stops — and the note says so. A feed without a calendar shows the whole network and says the service window is unknown instead of presenting whole-feed data as today's schedule.

  • Times past midnight stay past midnight. GTFS expresses a departure after the service day's midnight as hours beyond 24 (25:10). Rendering that as 01:10 fits the eye and misleads the decision, so it renders as recorded, in the feed's own timezone.

  • Edges are structure; schedules attach to nodes. The adjacency survives a no-service day because an agent walking between stops still wants it.

  • Live delays when you point GTFS-Realtime at it. Set SUPERCARTO_GTFS_RT to the agency's TripUpdates URL and predictions join onto the schedule: node lines gain a live: attribute such as bus 16 +300s or bus 16 cancelled, and the note says how fresh the feed is. Spec precedence holds — an explicit stop update beats the trip-level delay; absolute-time predictions convert through the feed's timezone. The honesty rule that matters most: a stop with no live entry is unknown, not on time, and the note says so in words. A feed that will not read (404, timeout, malformed data) degrades to the pure schedule answer with a one-sentence explanation, never a silent drop.

  • Next departures, not just the day's window. A next: attribute on each node lists the upcoming departures at that stop, in feed time order and in the feed's clock (tram 9 25:10 stays past midnight), capped at three with the hidden rest counted (+2 more). With a realtime feed configured the board speaks the prediction inline — bus 16 07:05 +300s or cancelled — and the live: list omits anything the board already said, so nothing prints twice. When the day's last departure has run, the note says the day is over instead of letting an empty board read as a broken feed.

  • A certified ride plan between two coordinates. get_transit_route walks to a stop, rides one line that serves both catchments, and walks it off — all straight-line legs labelled as such, never an interchange the feed cannot prove. Plans ride on the departure board's honesty: certified against the service day, predictions decorate their trips, cancelled trips drop out with a counted note, and when nothing can be certified the note names the leg that failed.

  • The signal is explicit. Departure times, the schedule date, and the feed's timezone travel in the note, where a model reading only the map sees them.


The budget is a real budget

Most map-for-agents code truncates and hopes. supercarto treats truncation as a correctness problem:

  • Ranking. Named landmarks survive; anonymous intersections are cut first.

  • Connectivity. Cut vertices are never removed, so the surviving network stays connected. A map the agent can traverse but not connect is worse than a smaller map it can use.

  • No stranded names. A landmark the agent can see but cannot route to is removed. It would confidently try to walk to it.

  • Verification. emitAndVerify re-measures the actual emitted YAML and cuts again until it fits. The reported budget is the budget delivered, not an estimate.

  • Honesty. Every drop is recorded in omitted:, aggregated per layer, so the model can tell "not there" from "not shown".


The benchmark

Lives in its own repo now: supercarto-bench.

Same question, same model, same map — the only variable is what sits in the context window: compiled graph vs raw GeoJSON vs nothing. Raw runs, frozen test maps, and the scoring code all live there, so anyone building a rival map tool can run the same test and try to beat the score.

Current headline there: 9/9 for the compact graph against ~4/9 raw and 0/9 with no map, on two AI models. Route questions are unmeasurable (the public test router gives impossible answers) — so route is demoted to a feasibility answer: straight-line distance, compass direction, then "verify the approach on arrival". Turn-by-turn requires a router you host and have verified; OSRM is opt-in, not default. Stated, not hidden.

The score now ships with its own reproduction recipe (scoreC certificate, re-derived from raw answer archives without model calls), a per-model leaderboard, and adapter arms: a rival tool registers itself with a single { name, prepare } module and gets the same tasks, models and pass rules. The current certificate: supercarto 38/47 · geojson 15/44 · none 0/47 across every archived run.

  • Live certificate — every number, re-derivable from committed archives with no model calls.

  • Live leaderboard — per model and per arm, including the free models you can run yourself.

What this repo keeps is a quick token-cost check:

npx supercarto bench <file.geojson>

Data sources

Source

Status

Use

Overpass

default

Development. 15-40s per call, rate limited.

PMTiles / Protomaps

SUPERCARTO_PMTILES

Production. Range requests against object storage, milliseconds, no rate limit.

OSRM

default

Turn-by-turn routing, walk/bike/drive.

Open-Meteo

default

Weather. No key.

TomTom / HERE

key required

Live traffic.

Terrarium tiles

default

Elevation and slope. No key.

GTFS feeds

SUPERCARTO_GTFS

Transit stops, lines, and schedules. Any static feed, no key. Live delays join from a GTFS-Realtime TripUpdates URL via SUPERCARTO_GTFS_RT.

export SUPERCARTO_PMTILES=https://your-bucket/planet.pmtiles

PMTiles is the answer at production volume. The reader is included — no pmtiles dependency, no mapbox-gl, zero transitive packages.

Everything is read from the environment by one factory, so the CLI and the MCP server cannot disagree about where data came from. They did once, and nothing reported it.

SUPERCARTO_PMTILES      PMTiles archive URL; primary source when set
OVERPASS_ENDPOINT       your own Overpass instance
TERRARIUM_ENDPOINT      elevation tile template
TOMTOM_API_KEY          enables get_traffic
HERE_API_KEY            enables get_traffic
SUPERCARTO_NO_TERRAIN   disable elevation
SUPERCARTO_NO_WEATHER   disable weather
SUPERCARTO_GTFS         path to a GTFS feed (dir or .zip); enables get_transit
SUPERCARTO_GTFS_RT      TripUpdates URL; adds live delay lines to get_transit

Attribution and the BYO-key contract

supercarto never ships keys. You configure every source with your own credentials, so every upstream relationship — Open-Meteo, TomTom, HERE, a transit agency's feed — is a direct one between you and the provider:

  • Traffic without a key returns free-flow, labelled. get_traffic is absent from tools/list until TOMTOM_API_KEY or HERE_API_KEY is set, and a free-flow estimate always says "free flow" in its own output. A congestion-free answer presented as live is the one failure this library refuses on principle.

  • Weather and air without a key use the non-commercial Open-Meteo API. That free tier is explicitly non-commercial: under 10,000 calls/day and not for products, subscriptions, or ad-supported apps. A commercial deployment gives it its own Open-Meteo subscription and endpoints, and the terms stay between you and OpenMeteo GmbH. Attribution is stated either way: weather and air answers name their source, and the Open-Meteo CC BY 4.0 term is spelled out.

  • Transit answers only what your feed proves. The feed comes from SUPERCARTO_GTFS; the note lines name it, its timezone, and its service date. Some agencies license their feeds with agency-specific terms — check the feed you import before a commercial deployment.

  • Attribution rides on the answer, not in it. ODbL is a licence term, so every REST response carries X-Data-Attribution: © OpenStreetMap contributors (ODbL) and an attribution field in the JSON body, and MCP map answers carry the same line in a comment. The compiled document itself is untouched — the attribution costs tokens at transport level only.

Nothing abhors a key like a self-hosted install, and nothing is attributed except what was actually fetched: arithmetic carries no line, and a custom weather or air source is named by its own name rather than handed a licence it did not grant.

Whole-metro feeds load entirely into memory. Since 0.6.1 the load is columnar — stop_times go straight into per-trip arrays, no row objects — so a feed the size of Translink SEQ (35 MB zip) fits Node's default heap and the answer is byte-identical to the pre-0.6.1 build. Verified live at that size: schedule, departure boards, and 750+ realtime predictions join in one answer with no NODE_OPTIONS at all. Bigger feeds load in proportion to their own inflated size; give such a run NODE_OPTIONS=--max-old-space-size=4096.


Agent integration

Claude Desktop (one-click)

Every release ships supercarto-X.Y.Z.mcpb — an MCPB bundle: download it from the latest release, open it with Claude Desktop, and the maps tools install with one click. Optional install-time configuration: an Open-Meteo key for higher weather limits, and a local GTFS feed path (plus the operator's TripUpdates URL) for the transit tools. Node ≥ 18 is the only requirement; the bundle carries the server, which has zero npm dependencies, so it is half a megabyte.

MCP

{
  "mcpServers": {
    "supercarto": { "command": "npx", "args": ["supercarto", "mcp"] }
  }
}

Eight tools: get_maplet, route, search_places, expand_feature, get_daylight, get_terrain, get_weather, get_air, plus get_traffic when a key is present, get_transit and get_transit_route when a GTFS feed is configured. Each maplet lists exactly the tools that deployment can answer, so an agent never calls one that cannot work. get_daylight is always available: sun position is arithmetic, needing no source and no credential. get_weather and get_air are keyless by default: an agent never tells someone it is safe to go out without knowing rain or air first.

What a maplet says about a place

Beyond topology and distance, a node can carry the facts that decide whether a trip is worth making:

n3: {type: poi, name: Blue Bottle, tags: [cafe], hours: 07:00-18:00, brand: Blue Bottle}
n4: {type: poi, name: Central Rx, tags: [pharmacy], hours: 09:00-17:00}
map:
  sun: up, elevation: 43.4deg, twilight: day, azimuth: 22deg, sunrise: "..."

Both shops above are open at 12:00 local. At 04:00 the same two read hours: closed, because their hours are known and they are shut. A bench with no recorded hours emits no hours field at all.

hours is evaluated against an instant and evaluated in the map's timezone, not the server's. Three states, never two: a time range, closed, or absent because nobody recorded it. Absent is deliberately not closed — those lead to opposite advice, one means go and find out, the other means go elsewhere.

twilight is day, civil, nautical, or night rather than a boolean, because the three lead to different decisions: walking is fine at civil twilight and unwise at nautical. Above the Arctic circles in summer and winter the map reports polar: day or polar: night instead of inventing a sunrise.

Pass compile.utcOffsetMinutes and compile.now to fix both to a known place and instant, which is what the tests do.

Python

import asyncio
from supercarto import SuperCarto

async def main():
    async with SuperCarto() as carto:
        m = await carto.maplet(lat=35.6833, lon=139.7620, radius_m=400, budget=1500)
        print(m.yaml)
        w = await carto.weather(lat=35.6833, lon=139.7620)

asyncio.run(main())

Zero runtime dependencies. It speaks JSON-RPC to the Node server over stdio rather than importing an SDK, because the mcp package pulls in httpx and pydantic and an agent framework that already depends on one of them should not get a second copy.

HTTP

curl 'localhost:8787/maplet?lat=35.6833&lon=139.762&radiusM=400&budget=1500&format=yaml'

Hosted mode (deployed)

The compile path is Workers-compatible (fetch-based sources, no Node built-ins), and cloud/worker/ packages it as a Cloudflare Worker: the same /maplet, /scr, weather, daylight and terrain surface as the local HTTP API above, with per-IP rate limiting and ODbL attribution on every map response. It is deliberately a subset — transit and traffic are not served, because a Worker has no filesystem for a GTFS feed and hosted mode ships no flow-provider keys, and GET / states that openly. See cloud/worker/README.md.

Deployed at https://supercarto-compile.jeffrinjames99.workers.dev. Data source chain for /maplet and /scr: live Overpass first, then a hosted PMTiles planet build of the OpenStreetMap basemap — every known public Overpass instance refuses the shared Cloudflare egress range (HTTP 521), so the fallback is what actually serves a hosted maplet. The archive's detail level is coarse beyond z10-ish, and the deployment caps a request's tile and feature fetches so a planet tile stays inside a Worker CPU budget; truncation travels in the document as warnings, and the source: line says protomaps when the fallback served it. Weather, daylight and rate limiting are live; terrain answers an honest 503 (Terrarium tiles are PNG-encoded and the bundled zero-dependency decoder reads raw Terrarium buffers only); transit and traffic are absent for the reasons GET / lists. GET /healthz probes Overpass only, so a 503 there means the Overpass leg is unreachable — not that the PMTiles fallback is down.


CLI

supercarto fetch --lat 35.6833 --lon 139.762 --radiusM 400 --budget 1500 --metrics
supercarto weather --lat 35.6833 --lon 139.762 --hours 12
supercarto traffic --from 37.7749,-122.4194 --to 37.7849,-122.4194
supercarto transit --feed city-gtfs.zip --lat 36.913 --lon -116.77 --radiusM 3000
supercarto route --from 37.7749,-122.4194 --to 37.7849,-122.4194 --mode walk
supercarto mcp
supercarto serve --port 8787
supercarto compile city.geojson --budget 1024 --metrics
supercarto encode city.geojson --out city.scr
supercarto decode city.scr
supercarto bench city.geojson

fetch layers accept road and poi alongside raw OSM tags; anything else is rejected rather than silently returning nothing. A request that would yield named places with no streets fails with a clear error instead of a misleading map — pass --layers poi for a POI-only map. Warnings travel inside the map output, not just stderr, so agents see them.


Accuracy

Distances are verified against haversine ground truth at mid and high latitude:

  • 0.11% error at San Francisco (37.77°N)

  • 0.11% error at Oslo (59.91°N)

This required getting the Web Mercator scale correction right: mercator distances exceed ground distance by 1/cos(latitude) on both axes, and getting the sign wrong produces a 26% error at mid latitude that compounds toward the poles. A mean isotropic scale is also wrong for a non-square bbox, so the scale is applied per axis.

The benchmark task set spans 64°N to 33°S deliberately. A benchmark run only at 37°N measures one case and hides every sign error toward the poles.


Status

461 tests passing: 328 unit (including 42 for the GTFS transit layer, 14 for the protobuf wire and TripUpdates schema, 5 for the real-time overlay join, and 7 for the PNG elevation decoder), 121 against live sources, and 12 MCP end-to-end. Outputs are byte-identical to the Python port - the parity engine runs on every push. Verified against live OpenStreetMap, live Open-Meteo, and the live MCP server driven from Python.

Implemented: SCR codec (text and binary, delta geometry, ring groups, three heat encodings, omissions, routes, refs), Web Mercator with per-axis scale correction, Visvalingam-Whyatt simplification, GeoJSON ingestion with OSM classification, topology compilation with junction welding and landmark attachment, token budgeting with connectivity guarantees, YAML emission, indoor floor graphs with vertical circulation, place-density heatmaps, live Overpass, PMTiles with a built-in MVT decoder, routing demoted to feasibility (straight-line distance and direction by default; OSRM turn-by-turn is opt-in for an engine you have verified — the public demo router returns impossible distances), keyless weather with a degraded path that refuses to invent readings, traffic with an honest free-flow fallback, terrain elevation and slope, GTFS transit schedules with three honest service states, GTFS-Realtime trip updates joined onto those schedules with unknown-not-on-time semantics, MCP over stdio, HTTP API, CLI, a Python client, and a task-level benchmark with OSRM ground truth.

Not implemented: hosted vector tiles with style delivery, and full indoor room geometry beyond centroids.


License

Apache-2.0

Available Tools

9 tools
expand_featureA

Fetch the exact geometry of features by id, as WKT. Use only when shape matters, such as checking whether a route clears a building.

NameRequiredDescriptionDefault
idsYes
scrYesSCR document from a previous get_maplet.

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It discloses that this is a read/fetch operation and that the response is WKT geometry, but says nothing about permissions, error behavior for unknown IDs, or whether it returns one or many geometries.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences, front-loaded with the action and output format, followed by a tightly scoped usage condition and example. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter read tool with no output schema and no annotations, the description adequately covers what it returns (WKT geometry) and when to use it. Minor gaps remain around where IDs come from and error handling, but the core invocation context is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 50%: the 'scr' parameter is documented in the schema, while 'ids' is undocumented there. The description adds 'by id' and clarifies the fetched result is exact geometry, but does not explain the ID source or relationship to the SCR document.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Fetch the exact geometry of features by id') and adds the output format ('as WKT'). It also implicitly distinguishes itself from map-display siblings by saying to use it only when shape matters, so an agent can select it without opening other schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit usage guidance with 'Use only when shape matters' and a concrete example ('checking whether a route clears a building'). It does not name the alternative tool to use for non-shape queries, so it stops short of fully explicit routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_airA

Air quality at a coordinate: European and US AQI bands, particulate load, and the forecast window. Use this before sending someone into prolonged outdoor exertion, or before recommending a walking route to a person with respiratory sensitivities.

NameRequiredDescriptionDefault
latYes
lonYes
hoursNoForecast horizon in hours. Default 12, max 48.

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden. It does disclose the conceptual payload (both AQI standards, particulate load, forecast window), which is real behavioral value, but says nothing about data freshness, source, whether an API key is needed, or how invalid coordinates or out-of-range horizons are handled.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: the first front-loads what the tool returns, the second gives the decision context. Nothing is repeated and nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no annotations and no output schema, the description does the heavy lifting well by enumerating the returned data and the use case. It falls short of full completeness only on operational details — provenance/freshness of readings and error behavior — which matter for a data-fetch tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33% — only 'hours' is documented (default 12, max 48). The description compensates by framing input as 'a coordinate' and output as a 'forecast window', which maps lat/lon and the horizon semantics, though it adds no tolerance, format, or range detail for the coordinates themselves.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (air quality at a coordinate) and enumerates the returned data: European and US AQI bands, particulate load, and forecast window. That scope cleanly separates it from get_weather, get_terrain, and get_daylight without the agent needing to open any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives two concrete, actionable when-to-use triggers: before prolonged outdoor exertion, and before recommending a walking route to someone with respiratory sensitivities. It omits explicit when-not conditions and never names an alternative sibling for overlapping queries (e.g. general weather), which keeps it below a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_daylightA

Sun position, sunrise, sunset, and twilight state for a coordinate. Twilight is reported as day, civil, nautical, or night rather than a boolean, because "needs a torch" and "cannot see" are different states.

NameRequiredDescriptionDefault
atNoISO 8601 instant. Defaults to now. Times are UTC.
latYes
lonYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations, so the description carries the burden. It discloses the shape of the return conceptually (categorical twilight states rather than a boolean) and explains why, which is genuinely useful, but it says nothing about whether times are returned as instants vs. local strings, what 'sun position' looks like numerically, or any rate/permission constraints. Read-only is inferable only from the 'get_' name.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the returned quantities, then a short design note that prevents a wrong expectation (boolean vs. four-state twilight). Nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations, the description does well to enumerate the returned quantities, but an agent still cannot predict the serialized form — time format of sunrise/sunset, units for sun position, or field names. For a 3-parameter lookup returning multiple values, that is a real gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 33% — only 'at' is documented in the schema. The description adds only 'for a coordinate', which maps lat/lon to location but gives no sign convention, unit, or precision guidance, and never mentions the optional 'at' override or UTC/Earth-time handling.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete resource ('sun position, sunrise, sunset, and twilight state') with its required input ('for a coordinate'), which makes it unmistakable against siblings like get_weather and get_terrain. The clarifying note about how twilight is reported reinforces exactly what this tool returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: 'for a coordinate' and the twilight rationale hint at daylight/visibility decisions, but there is no explicit when-to-use, when-not-to-use, or named alternative (e.g., get_weather for cloud cover that would make twilight moot).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_mapletA

Fetch real map data around a coordinate and return a token-budgeted topological graph: named places joined by walkable edges with distances in metres and compass directions. Use this to answer 'what is near X' and 'how do I get from A to B'. Omissions are reported, so treat a missing feature as not-shown rather than absent.

NameRequiredDescriptionDefault
latYesLatitude in WGS84 degrees.
lonYesLongitude in WGS84 degrees.
budgetNoToken budget for the response. Default 1024, hard cap 8192.
layersNoSemantic layers to include, e.g. ["road", "poi"]. Default all.
radiusMNoRadius in metres. Default 300. Larger costs more tokens.
returnScrNoAlso return the wire SCR in a second content block. Keep it: it is the session state a later localize() call moves within, and the agent stores it in its own RAM rather than the chat context.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does well: it discloses that output is token-budgeted, that results form a topological graph, and that omissions are reported so missing features should be treated as not-shown rather than absent. It does not explicitly state read-only/no side effects, but 'Fetch' strongly implies it.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core action and output shape, then use cases, then an important caveat about omissions. Every sentence earns its place without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a six-parameter graph-fetch tool with no output schema and no annotations, the description explains the returned graph, edge attributes, token budgeting, and omission semantics. It could say more about response structure or layer effects, but what is present is sufficient for an agent to understand the call's result and caveats.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters in detail, including defaults, token cap, layers, radius, and returnScr. The description mentions token budgeting but does not add parameter-level meaning beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: fetch real map data around a coordinate and return a token-budgeted topological graph. It clearly states the key output elements, named places joined by walkable edges with distances and directions, but does not explicitly distinguish this from siblings such as route or search_places.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit use cases: answering 'what is near X' and 'how do I get from A to B'. However, it provides no when-not-to-use guidance and does not name alternatives like route or search_places, leaving the sibling routing overlap unresolved.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_terrainB

Sample ground elevation around a coordinate, in metres. Returns the range plus high and low points, which is what an agent needs for grade reasoning.

NameRequiredDescriptionDefault
latYes
lonYes
radiusMNo
samplesNo

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden; it does disclose units (metres), the sampling concept, and the return shape (range plus high/low points). It omits important behavioral caveats such as data resolution/accuracy, cost or rate limits, and behavior when the coordinate falls outside coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no filler; the core action and result are front-loaded in the first clause. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description gives only a one-line sketch of the return values, which is roughly adequate. However, for a four-parameter geo tool with zero schema descriptions, the missing parameter and data-quality detail leaves the definition only minimally complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% for four parameters, so the description must compensate. It vaguely gestures at a 'coordinate' and sampling 'around' it, but never names lat/lon, never explains that radiusM is in metres with a 1000 m default, and says nothing about the 'samples' count or its default of 16 — 'in metres' is even ambiguous between elevation and radius.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Sample ground elevation around a coordinate') plus the output shape (range, high and low points). It is clearly distinct from siblings like route, get_weather, or get_daylight, though it never explicitly contrasts with them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'which is what an agent needs for grade reasoning' implies the intended use case, but there is no explicit when-to-use/when-not-to-use guidance and no mention of alternatives for elevation-adjacent needs. Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_weatherA

Current weather conditions and a short forecast at a coordinate. Use this before telling someone to walk, cycle, or drive, or to pick between an indoor and outdoor option. Reports what is actually falling (rain, snow, sleet) rather than only a temperature.

NameRequiredDescriptionDefault
latYes
lonYes
hoursNoForecast horizon in hours. Default 12, max 48.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses the character of the data ('reports what is actually falling... rather than only a temperature'), but says nothing about permission needs, units, failure modes, or what the response contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences: purpose front-loaded, then usage trigger, then a differentiator. No filler, and each sentence adds a distinct piece of information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter, no-annotation, no-output-schema tool, the description covers purpose and usage but leaves coordinate units, forecast horizon, and returned data shape unaddressed. Adequate to select the tool, thin for calling it precisely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 33%, so the description should compensate but mostly doesn't. 'At a coordinate' implies lat/lon without specifying units or format, and it never mentions the hours horizon parameter, whose default/max is only documented inside the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence gives a specific verb+resource+scope: current conditions and a short forecast at a coordinate. It is clearly distinct from terrain or daylight siblings by domain, but it never names or contrasts a sibling explicitly, so it stops short of the top score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states concrete triggering situations (before recommending walk/cycle/drive, or choosing indoor vs outdoor), which is clearer than typical implied usage. It offers no when-not guidance and does not point to an alternative tool for other weather needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

localizeA

Move within a map session you already hold. Pass the session SCR (from get_maplet with returnScr, or from the last localize) and your new position; the answer is only the delta: + places that entered view, - places that left it, ~ places that moved or updated. Store the updated SCR from the second content block and discard the old one.

NameRequiredDescriptionDefault
latYesLatitude in WGS84 degrees.
lonYesLongitude in WGS84 degrees.
scrYesSession state: the SCR string from the previous get_maplet or localize.
budgetNoToken budget for the re-fit view. Default 1024, hard cap 8192.
layersNoSemantic layers to include, e.g. ["road", "poi"]. Default all.
radiusMNoRadius in metres. Default 300.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses the state-mutation lifecycle (store the updated SCR from the second content block, discard the old one) and the return semantics (delta only: + entered, - left, ~ moved/updated). It does not cover error behavior or what happens if the SCR is stale, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the core action and ending with the critical state-maintenance instruction. Every clause carries operational value with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

It compensates for the missing output schema by explaining the delta return format and the two-content-block structure, and covers the important stateful behavior. Minor gap: the optional budget/layers/radiusM parameters are not mentioned, though the schema documents them fully.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents lat/lon, scr, budget, layers, and radiusM. The description adds a little beyond the schema by emphasizing the SCR rotation rule, but adds no syntax or format detail for the geographic or budget parameters; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Move within a map session') and distinguishes it from get_maplet by describing it as motion inside an existing session. An agent can tell it apart from the session-creating sibling without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames it as operating on a session 'you already hold' and names where the SCR comes from (get_maplet with returnScr, or the last localize), which implies the correct sequencing. It stops short of explicitly saying not to use this for an initial fetch or how it differs from route, but the prerequisite is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

routeB

Feasibility between two coordinates: straight-line distance, the compass direction to head, and nothing that pretends to be turn-by-turn navigation. Turn-by-turn comes only from a routing engine the operator has verified; the default answer ends in "verify the approach on arrival", which is the honest limit of what it computes.

NameRequiredDescriptionDefault
modeNowalk
toLatYes
toLonYes
fromLatYes
fromLonYes

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose one genuinely useful behavioral trait: the default answer appends a 'verify the approach on arrival' caveat, and no turn-by-turn data is computed. However, it says nothing about units, coordinate ordering assumptions, error behavior, or what the 'mode' parameter actually changes if distance is straight-line.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core capability is front-loaded in the first clause, which is good, but the second half is editorial prose that restates the same disclaimer about turn-by-turn navigation twice. It is not bloated enough to bury the point, but sentences could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no annotations and no output schema, the description is the only source of truth, and it does convey the substance of the return (distance, direction, a caveat string). It still leaves gaps an agent needs for correct invocation: units, response format, and the effect of mode.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across five parameters, so the description must compensate. It only implies that fromLat/fromLon and toLat/toLon form the two coordinate pairs; it never explains units, precision, ordering, or the role of the walk/bike/drive enum, which is left entirely opaque.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a concrete output set: straight-line distance and compass bearing between two coordinates. It sharply disambiguates itself from a true routing engine by denying turn-by-turn capability, so an agent knows exactly what it will and will not get. It does not distinguish itself from any sibling tool by name, which keeps it below a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: the word 'Feasibility' and the denial of turn-by-turn suggest a quick sanity check, not navigation. There is no explicit 'use this when…, use X instead' guidance, and no sibling (get_maplet, localize, search_places) is named as an alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_placesA

Find named places (cafes, stations, shops) near a coordinate. Cheaper than get_maplet when only names are needed.

NameRequiredDescriptionDefault
latYes
lonYes
limitNo
queryNoSubstring match on place name or type.
radiusMNo

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the behavioral burden; it does disclose the cost tradeoff versus get_maplet, which is genuinely useful. It says nothing about return shape (names only, or with type/distance?), result ordering, or how radius/limit affect recall, so an agent cannot predict output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences, zero filler, with the core purpose front-loaded and the sibling comparison as a secondary clause. Every phrase earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter tool with no annotations and no output schema, the description covers purpose and the sibling tradeoff but leaves output content and the radius/limit behavior unexplained. Adequate to call the tool, not adequate to predict what comes back.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 20% — just the `query` property is documented — and the description does not compensate. It never mentions that limit defaults to 20 or that radiusM defaults to 300m, a value that materially constrains results; only lat/lon are implied by "near a coordinate".

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (Find) plus resource (named places) with concrete examples and a spatial scope (near a coordinate). It also explicitly distinguishes itself from get_maplet, so an agent can pick between them without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Cheaper than get_maplet when only names are needed" names the alternative and the condition that selects it, implying get_maplet is for richer detail. It gives no guidance on the other siblings (route, localize, expand_feature), but the core routing decision is covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev0.7.0
    • Addedget_air
  2. 8 tool updatesv0.1.0
    • First observedexpand_feature
    • First observedget_daylight
    • First observedget_maplet
    • First observedget_terrain
    • First observedget_weather
    • First observedlocalize
    • First observedroute
    • First observedsearch_places

TDQS

A3.7/5.0

Scored across 9 tools

Disambiguation4/5

Each tool maps to a distinct data concern (terrain, air, daylight, weather, geometry, places, routing, session delta), and descriptions explicitly steer callers between near-duplicates like search_places vs get_maplet. The one soft overlap is route vs get_maplet, both of which claim to answer 'how do I get from A to B', though route's straight-line-only framing partially disambiguates them.

Naming Consistency4/5

Seven of nine tools use a predictable get_/verb_noun pattern (get_terrain, get_air, get_daylight, get_weather, get_maplet, search_places, expand_feature). expand_feature, localize, and route break the prefix convention but remain clear single-verb names, so the deviation is minor rather than confusing.

Tool Count5/5

Nine tools is well within the sweet spot, and each covers a genuinely different facet of geospatial context rather than duplicating another. Nothing feels padded or conspicuously absent from the surface.

Completeness4/5

The set covers environmental context (terrain, air, daylight, weather), place discovery, geometry expansion, session-based panning, and route feasibility — a solid lifecycle for location reasoning. The main gap is forward geocoding (resolving an address or place name to a coordinate), which agents would need before using most other tools.

Maintenance

ActivityActive
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables location-aware AI agents to search for nearby places, get detailed place information including hours and ratings, and calculate routes with turn-by-turn directions using Google Maps APIs.
    22
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables AI agents to become geospatially intelligent assistants with tools for location search, smart routing, round trip planning, reverse geocoding, isochrone analysis, route visualization, geofence management, and interactive map display.
    8
    17 npm
    7
    Apache 2.0