Skip to main content
Glama
atlasfetch-dev

atlasfetch-mcp

Official

atlasfetch-mcp

No signup needed to try it: without a key it falls back to a shared public demo key, capped at 1,000 lookups a month across everyone using it. Get your own limits with a free sign-up at atlasfetch.xyz.

An MCP server for AtlasFetch — reverse geocoding to administrative boundaries and streets, and geofencing, as tools your AI assistant can call directly.

Ask "which municipality is -33.9249, 18.4241 in?" and get Cape Town, Western Cape, South Africa with ISO 3166 codes — from a real point-in-polygon lookup, not the model's memory.

country: United Kingdom (GB) · region: England (GB-ENG) · municipal: City of Westminster (GB-WSM)

What it does

Tool

What it does

lookup_location

A coordinate becomes the country, region and municipality containing it, with ISO 3166-1 / 3166-2 codes, plus matches from your own boundary sets. Optionally the nearest street (ask for the street layer), and the point as an H3 cell or Google Plus Code.

geocode_address

An address becomes a point, in South Africa today, with a precision that says whether the house, the street or only the suburb was found — and what to do about it.

get_route

A route between 2 and 25 coordinates by car, bike, foot or truck, with turn-by-turn steps — optionally around your own zones, or measuring how far it runs inside them.

list_boundary_sets

Lists your boundary sets, their counts, and which API keys may query them.

create_boundary_set

Creates an empty set for your own polygons.

add_boundary

Adds one GeoJSON polygon, with properties returned on every match.

update_boundary

Moves or reshapes one boundary, keeping its id, name and properties.

Good for: reverse geocoding to administrative areas, finding the street a point is on, geofencing against your own delivery zones or service areas, jurisdiction and region checks, tagging location data with region codes, geocoding delivery addresses in South Africa, and routing that keeps out of the areas you name.

Not for: geocoding outside South Africa (yet), searching for places by name, traffic-aware ETAs, distance matrices, isochrones, map tiles, or downloading boundary geometry.

Directions

get_route returns distance, duration and turn-by-turn steps between 2 and 25 coordinates, for car, bike, foot or truck.

car: 3.5 km · 5 min · 11 steps · a location moved 62 m to reach a road — free-flow, no traffic

Three things worth knowing before you wire it up:

  • A route costs 10 lookups, not one. Everything it returns is included in that, but it is ten times a lookup.

  • Durations are free-flow — the network at its own speed limits, with no live or historical traffic. They are not ETAs. For those, use a traffic-aware service.

  • The route line is off by default (routeGeometry: "none"). An encoded polyline is thousands of characters an assistant cannot read; ask for polyline6 or geojson only when something will draw it.

Your own zones, in a route. avoidSets names boundary sets to route around; exposureSets names sets to measure against, leaving the route alone and reporting how many metres of it ran inside each zone. A zone containing one of your locations cannot be avoided for that route — it is skipped, and the answer says so.

Plan limits apply: 2 locations on the free plans and up to 25 on Pro, truck is Pro only, and alternatives need exactly 2 locations. Over a cap the answer is a 403 and nothing is billed; a location with no road near it is a 422, and that one is billed, because the route was attempted.

Geocoding

geocode_address turns one address into a point — q on one line, or address already split into parts. South Africa today.

address · confidence 0.96 · 25 Adderley Street, Cape Town, ZA-WC — dispatch
street · confidence 0.47 · ambiguous · Long Street, Cape Town, ZA-WC — ask the customer before dispatching

Read the precision before you use the point. address is the house; interpolated is estimated between the numbers either side; intersection is a street corner ("Cnr Main Rd and Belmont Rd"); site is a named place such as a shopping centre, office park or hospital (pass the shop or unit number on to the driver); street is the right street but not the house; locality is only the suburb. The result line applies the API's own advice for deliveries: dispatch only on a house-, corner- or site-level answer that is not ambiguous, ask the recipient for a pin on a street-level one, and ask the customer when it is ambiguous. In South Africa most answers are street-level, because OpenStreetMap has house numbers on about 13% of street names.

One address per call, at 1 lookup each, found or not. That is deliberate: a delivery list goes through one row at a time, where you can see what it spends. Programs with thousands of rows should call POST /geocode/batch on the API directly.

Streets

Add the street layer and the answer includes the nearest street, and the house number where one is mapped. It is worldwide, and opt-in — not part of the default country, region, municipal.

You always get three answers — for 5 m, 20 m and unlimited — because "the nearest street" depends on how far you are willing to look:

"street": [
  { "radiusMeters": 5,    "streetNumber": null, "streetName": "Adderley Street", "postcode": null,   "distanceMeters": 2.7 },
  { "radiusMeters": 20,   "streetNumber": "25", "streetName": "Adderley Street", "postcode": "8001", "distanceMeters": 9.6 },
  { "radiusMeters": null, "streetNumber": "25", "streetName": "Adderley Street", "postcode": "8001", "distanceMeters": 9.6 }
]

Two nulls that mean different things: "street": null means there is no street data for that country, while an entry whose fields are null means nothing was within that radius. streetNumber and postcode are strings (44A, 12-14, 0181); house numbers are rare outside well-mapped areas. Set streetGeometry and each answer also carries the street's line, trimmed to about 250 m — leave it off unless something will draw it.

Related MCP server: Location MCP Server

Install

Claude Code

claude mcp add atlasfetch -- npx -y atlasfetch-mcp

Claude Desktop, Cursor, VS Code and other clients

Add to your MCP config (claude_desktop_config.json, .cursor/mcp.json, or your client's equivalent):

{
  "mcpServers": {
    "atlasfetch": {
      "command": "npx",
      "args": ["-y", "atlasfetch-mcp"],
      "env": {
        "ATLASFETCH_API_KEY": "your-key-here"
      }
    }
  }
}

Requires Node 20 or newer.

Getting a key

The demo key is shared by every anonymous user on the internet — one pooled quota and rate limit. Fine for a first look, wrong for anything real.

Create your own at atlasfetch.xyz/dashboard and set ATLASFETCH_API_KEY. The free Personal plan needs no card. You can copy a key from the dashboard at any time — so restrict it to your own domains there. Keys made before 12 October 2026 were revoked; if yours stops working, copy a live one.

Variable

Default

Purpose

ATLASFETCH_API_KEY

(demo key)

Your API key.

ATLASFETCH_API_URL

https://api.atlasfetch.xyz

Override only for local or staging APIs.

Two things that surprise people

municipal is the finest unit available, not a consistent kind of thing. Los Angeles returns a city; rural Kansas returns a county; some places return a district. Where a country's fine tier is patchy, a coarser complete tier answers instead, because a county beats null for most uses. Don't assume the value names a city.

A new boundary set cannot be made queryable from here. Sets are created switched off and granted to no key, and granting is addressed by API key id — which only a signed-in browser session can list. So this server can create a set and fill it, but the last step happens in the dashboard. create_boundary_set says so in its response rather than leaving you with a set that silently matches nothing.

Billing

A lookup or a geocoded address is one lookup; a route is 10 on the standard plans. A lookup is one, however many layers, sets or grid codes it touches. Metering happens before matching, so a lookup that matches nothing still counts. Requests rejected as invalid or rate-limited are not billed.

Conventions

A few rules hold across all seven tools, so an input means the same thing wherever it appears.

  • set names one set, sets names several. add_boundary and update_boundary act on one set (set). lookup_location and geocode_address match against any number of sets (sets).

  • get_route flattens two API objects. The API takes avoid: { sets: [...] } and exposure: { sets: [...] }. The tool takes avoidSets and exposureSets, because a one-key wrapper object is a step a model gets wrong.

  • …Geometry is always a line you ask to get back, and always off by default. routeGeometry on get_route, and streetGeometry on lookup_location and geocode_address. A plain geometry input is a polygon you send, on add_boundary and update_boundary. (get_route still accepts geometry as an old name for routeGeometry; it goes in 1.0.)

  • Where a default differs from the API's, it is on purpose:

    Tool

    Input

    This server

    API

    Why

    get_route

    steps

    true

    false

    Turn-by-turn is what someone asks an assistant for

    lookup_location

    streetGeometry

    adds street to base

    400 without street

    Asking for a street's line means asking for the street

  • The first line of every answer is for a person, and is not a contract. It summarises the answer and says what to do with it (— dispatch, — ask the customer), and its wording will keep improving. The JSON below it is the API's answer, unchanged, and that is what to parse.

Stability

Before 1.0, minor versions (0.3 → 0.4) may rename or remove an input, as 0.4.0 did, though always with a deprecated alias first.

From 1.0:

  • Frozen: tool names, input names, input types and defaults.

  • May change in a minor release: new tools, new optional inputs, new values an output can take (as intersection and site were added to precision), and the wording of descriptions and of the first line of each answer.

  • Breaking changes go through deprecation. The old form keeps working for at least one minor release, its description says what replaces it, and it is removed only in the next major version.

  • The JSON in each answer follows the AtlasFetch API, which versions its own contract in its OpenAPI spec.

Every release is described in CHANGELOG.md.

Development

npm install
npm run build
node scripts/smoke.mjs   # drives the built server with a real MCP client, against the live API

Licence

MIT for this server. Reference boundaries derive from OpenStreetMap under the ODbL; attribution and share-alike obligations pass through to you. Coordinates you look up are not stored.

Available Tools

7 tools
add_boundaryAdd a polygon to a boundary setA
Destructive

Adds ONE polygon to an existing boundary set on this account, so that lookup_location reports when a point falls inside it — delivery zones, service areas, sales territories. Each call creates a new boundary: calling twice with the same name stores two.

Before calling: the set must already exist (create_boundary_set). A set matches nothing in lookups until it is switched on and granted to an API key in the dashboard at https://atlasfetch.xyz/dashboard, which this server cannot do.

geometry must be a single GeoJSON Polygon — not a MultiPolygon, Feature or FeatureCollection. Positions are [longitude, latitude]. Each ring needs at least 4 positions and must be closed (last position equals the first); extra rings are holes. Self-intersecting shapes are rejected. To store a MultiPolygon, add each part separately.

Plan limits cap vertices per polygon (every position counts, including the closing one), properties per boundary and boundaries per set; a limit hit is refused with a message naming it. WITHOUT YOUR OWN KEY, the shared demo key is on the Public plan: at most 5 positions per polygon (a closed quadrilateral), properties only category (zone, area, route, place, other), color (green, blue, red, yellow, purple, orange) and priority (low, medium, high), and one set shared with every demo user, where adding to a full set silently deletes its oldest boundary. Never upload anything private with the demo key.

Returns the stored boundary: id, set, name, properties, pointCount and createdAt.

ParametersJSON Schema
NameRequiredDescriptionDefault
setYesName of an existing set on this account (see list_boundary_sets).
nameYesLabel returned when a looked-up point falls inside this polygon, e.g. "Zone A".
geometryYesA GeoJSON Polygon, e.g. {"type":"Polygon","coordinates":[[[18.40,-33.93],[18.40,-33.90],[18.44,-33.90],[18.44,-33.93],[18.40,-33.93]]]}.
propertiesNoOptional flat key/value pairs returned with every match: keys up to 32 characters, values a string (up to 256 characters), number or boolean. The demo key accepts only category, color and priority, from fixed lists.

TDQS

A5/5.0
Behavior5/5

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

Beyond the annotations, the description reveals key non-obvious behaviors: calling twice with the same name stores two boundaries, self-intersecting geometries are rejected, plan limits cap vertices/properties/boundaries and produce a refusal message, and a full demo set silently deletes its oldest boundary. This substantially complements the destructiveHint and idempotentHint annotations.

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?

The description is long but every paragraph earns its place: purpose, prerequisites, geometry constraints, plan limits, demo-key caveats, and return values. It is front-loaded with the core behavior and organized so an agent can scan the critical constraints quickly.

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

Completeness5/5

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

With no output schema, the description explicitly lists the returned fields: id, set, name, properties, pointCount, and createdAt. It also covers failure modes, plan limits, authentication prerequisites, and the destructive demo-key behavior, making the tool fully callable by an agent without needing external context.

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

Parameters5/5

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

Although the schema coverage is 100%, the description adds meaning the schema alone does not convey: duplicate names are allowed, every position including the closing one counts toward vertex limits, a MultiPolygon must be split into separate calls, and properties are restricted per plan. The geometry constraints and example also reinforce the schema's coordinate-order and closed-ring requirements.

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?

The description names a specific verb ('Adds'), a specific resource ('ONE polygon to an existing boundary set'), and a concrete effect on lookup_location. It clearly distinguishes itself from create_boundary_set by requiring the set to already exist, and from lookup_location by stating it is the tool that makes containment reportable.

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

Usage Guidelines5/5

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

Explicit before-calling prerequisites are given: the set must already exist via create_boundary_set, and it must be switched on and granted to an API key in the dashboard. It also gives a clear when-not-to-use instruction for MultiPolygons ('add each part separately') and warns against using the shared demo key for private data.

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

create_boundary_setCreate a boundary setA

Creates an empty named set to hold your own polygons: delivery zones, service areas, sales territories.

IMPORTANT, and not a bug: a new set is created unavailable and granted to no key, so it matches nothing until both are changed. Granting is addressed by API key id, and the only endpoint that lists key ids needs a browser session — which this server does not have. So this tool can create the set and add boundaries to it, but CANNOT make it queryable. Tell the user to finish that at https://atlasfetch.xyz/dashboard.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesA short name, used to reference the set in lookups: 1-32 letters, digits, hyphens or underscores, starting with a letter or digit.

TDQS

A4.3/5.0
Behavior5/5

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

Beyond the annotations (readOnlyHint false, openWorldHint true, etc.), the description discloses the critical non-obvious behavior: the new set is unavailable and granted to no key, matches nothing until changed, and cannot be made queryable because the server has no browser session. This is exactly the kind of hidden trait an agent needs.

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

Conciseness4/5

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

The description is front-loaded with the core purpose and then uses a clearly marked IMPORTANT block for the critical caveat. The warning is a little verbose but every sentence carries necessary information about the limitation and required user follow-up.

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 one-parameter creation tool with no output schema, the description covers the purpose, the hidden behavior, and the required external follow-up. It does not describe the response/return value, but that is not essential enough to drop below a 4 given the rich caveat.

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?

The input schema already has 100% description coverage for the single `name` parameter, including pattern and length. The tool description adds only the notion of a 'named set' and does not deepen parameter semantics beyond the schema, so a baseline score of 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?

The description opens with a precise verb and object: 'Creates an empty named set to hold your own polygons...' and gives concrete use cases. It is clearly distinct from siblings like list_boundary_sets, lookup_location, and add_boundary, which perform listing, lookup, and adding rather than creation.

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 clearly situates the tool as a creation step for polygon sets and warns that this tool cannot make the set queryable, instructing the agent to tell the user to finish at the dashboard. It lacks an explicit 'use X instead' comparison to sibling tools, but the context is clear enough.

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

geocode_addressGeocode an address to a coordinate (South Africa)A
Read-only

Turn ONE address into a point, with an honest account of how much of it was found. Built for deliveries. South Africa today; more countries as their data loads. 1 lookup per address, found or not.

Send either q (one line) or address (housenumber, street, suburb, city, postcode, unit) — never both. If the address is already split, send it split: it matches better.

READ precision BEFORE using the point. "address" means the house was found; "interpolated" means it was estimated between the numbers either side; "intersection" means a street corner ("Cnr Main Rd and Belmont Rd", "Bree & Strand Streets"), at the point where the two meet, with the second street in matched.crossStreet; "site" means a named site — a shopping centre, office park, complex or estate, hospital, school, airport or hotel — at a point inside it, named in matched.site; "street" means the right street but NOT the house; "locality" means only the suburb or town. NEVER present a street- or locality-level point as a door: a driver sent there will be at the wrong house. In South Africa most answers are street-level, because OpenStreetMap has house numbers on about 13% of street names — that is the data being honest, not a failure.

What to do with an answer — the result line says which applies:

  • address, interpolated, intersection or site, not ambiguous, confidence 0.5 or more: dispatch. For a site, pass on the unit or shop number from the original address ("Shop 12") — the answer does not include it, and the driver needs it.

  • street: ask the recipient for a pin or a landmark.

  • ambiguous, or locality: ask the customer before dispatching. confidence ranks answers; it is NOT a probability. ambiguous means a same-named street elsewhere scored about as well, or the street was a near-miss spelling with no house number to confirm it. result null means nothing trustworthy was found, and that still costs the lookup.

Some addresses name something that cannot be placed: an erf, stand, plot or farm portion (land parcels — there is no cadastre), a township stand, a PO box or private bag. Those parts come back in unmatched and the answer is the place named, at locality: ask the customer for a street address.

country is a hard filter; region (ZA-WC, or "Western Cape") only ranks streets inside it first, so a wrong province does not lose the address. An uncovered country is refused, unbilled, with the list of covered countries in the message — that message is the live coverage list; there is no other. sets and base answer "which delivery zone is it in" in the same call, at no extra cost.

One address per call, deliberately. For a delivery list, call this once per row so the user sees what is being spent; programs with thousands of rows should use the API’s POST /geocode/batch directly. Not for: searching for a business or landmark by name, or a coordinate to an address (that is lookup_location with the street layer).

ParametersJSON Schema
NameRequiredDescriptionDefault
qNoThe whole address on one line, e.g. "25 Adderley Street, Cape Town".
baseNoAdministrative layers to resolve at the found point.
setsNoBoundary sets on this account to match at the found point, e.g. delivery zones.
regionNoISO 3166-2 ("ZA-WC") or a name ("Western Cape"). A preference, not a filter.
addressNoThe address already split into parts. Needs at least a street. Use instead of q.
countryNoISO 3166-1 alpha-2, e.g. "ZA". A hard filter: only that country is searched.
streetGeometryNoThe matched street’s line, trimmed to about 250 m. Only if something will draw it.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare readOnlyHint/openWorldHint, so the description carries the operational burden and does so well: it discloses cost behavior (1 lookup per address even on failure, uncovered countries refused unbilled), the meaning of confidence vs probability, and the fact that ~87% of ZA addresses resolve only to street level. These are traits the annotations do not convey.

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

Conciseness4/5

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

Strongly front-loaded with the core contract. It is long, and a few passages (the shop-number aside, the repeated street/locality warnings) go beyond strict necessity, but nearly every sentence carries operational value for a genuinely complex geocoding contract.

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

Completeness5/5

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

Even with no output schema, the description explains the return surface an agent needs: precision values, matched.crossStreet/matched.site, unmatched parts, confidence, and result null semantics. For a 7-param tool with nested objects this is complete enough to call and interpret correctly.

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 100%, so the baseline is 3, but the description adds genuine meaning beyond it: q vs address are mutually exclusive ('never both'), country is a hard filter while region only ranks, and sets/base return zones at no extra cost. Some of this restates the schema (e.g. region 'a preference, not a filter'), keeping it short of a 5.

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 (turn ONE address into a point) and immediately distinguishes itself from siblings by naming lookup_location for reverse geocoding. It also carves out an explicit non-goal (business/landmark name search) so the agent can route correctly without opening 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 Guidelines5/5

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

Gives explicit when-to-use and when-not rules: dispatch criteria keyed to precision/confidence, when to ask the customer, when to use the batch API instead, and what is out of scope. It routes the agent to a concrete alternative (POST /geocode/batch) for multi-row programs.

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

get_routeRoute between coordinates, optionally avoiding your own zonesA
Read-only

A driving, cycling, walking or truck route from the first location to the last, via any in between, with distance, duration and turn-by-turn steps.

COST: a route is 10 LOOKUPS on the standard plans, not one (a custom plan may charge less; X-Lookups-Remaining is always the truth). Everything it returns is included in that, so do not call it in a loop to compare options without saying so.

Durations are FREE-FLOW: the road network at its own speed limits, with NO live or historical traffic. Never present one as an arrival time in traffic — for that, say a traffic-aware service (Google, Mapbox) is needed.

The route line is NOT returned unless routeGeometry is set, because an encoded polyline is thousands of characters that no one reads. Ask for it only when something will draw it.

Locations are SNAPPED to the nearest routable road, and locations[] in the response says how far each one moved. A large snapDistanceMeters means the answer starts somewhere else than asked — worth repeating to the user.

avoidSets and exposureSets name BOUNDARY SETS on the account (list_boundary_sets), not ad-hoc shapes. avoid routes around every zone in those sets; exposure leaves the route alone and reports how far it ran inside each zone. A zone containing one of the locations cannot be avoided for that route: it is skipped and reported in avoid.skipped.

TRUCKS (Pro only): a truck over 9 t, or with no weightTonnes, is capped at 80 km/h, as South African law caps goods vehicles; a lighter truck keeps car speeds. The vehicle’s height, width, length, weight, axle load and hazmat are checked against road limits where OpenStreetMap records them, which is not everywhere — a good start, not a legal clearance.

Limits by plan: 2 locations and 1 alternative on the free plans, up to 25 and 2 on Pro; alternatives need exactly 2 locations. Over a cap the answer is 403, and nothing is billed. A location with no road near it, or two places with no road between them, is 422 — and that one IS billed, because the route was attempted.

Not for: distance matrices, isochrones or live traffic (none exist yet), and not for which-area-is-this questions — that is lookup_location, at one lookup.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoTravel mode. Defaults to car. "truck" is Pro only; see TRUCKS above.
stepsNoTurn-by-turn steps per leg. Defaults to true here; set false for distance and time only.
vehicleNoTruck dimensions and load. Only with mode "truck"; rejected otherwise. Give weightTonnes: without it the truck is treated as heavy (over 9 t) and capped at 80 km/h.
geometryNoDEPRECATED: use routeGeometry, which takes the same values. Removed in 1.0.
languageNoLanguage for the step instructions, e.g. "en-GB", "de-DE", "fr-FR". Defaults to en-US.
avoidSetsNoNames of boundary sets on this account to route AROUND. Every zone in them is excluded.
locationsYesOrigin, any stops in order, then destination. 2 on the free plans, up to 25 on Pro.
alternativesNoAlso return up to this many other routes. Exactly 2 locations only. Plan-capped.
exposureSetsNoNames of boundary sets to MEASURE against: the route is unchanged, and the answer says how many metres of it ran inside each zone.
routeGeometryNoThe route line. Defaults to none. Ask for polyline6 or geojson only when something will draw it: it is long, and an assistant cannot read it usefully.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare readOnlyHint and openWorldHint; the description carries far more: cost of 10 LOOKUPS per call, free-flow durations with no live/historical traffic, geometry withheld unless routeGeometry is set, snap behaviour and snapDistanceMeters reporting, avoid-vs-exposure semantics with avoid.skipped, truck speed capping, and plan limits. It also discloses billing rules per error code (403 unbilled, 422 billed), which no annotation covers.

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

Conciseness4/5

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

Long, but front-loaded with purpose then cost, and sectioned with labels (COST, TRUCKS, Limits by plan) so the reader can skim. Almost every sentence carries operative detail; the truck paragraph is extended but earns its place against the vehicle parameter.

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

Completeness5/5

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

For a 10-parameter, nested-object, billing-sensitive tool with no output schema, the description still tells the agent what comes back (locations[] snap distances, avoid.skipped) and where the route line appears. Nothing needed to call it correctly or to set user expectations is missing.

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 100%, so baseline is 3, but the description adds meaning beyond the schema: avoidSets/exposureSets are account-level BOUNDARY SETS (pointing at list_boundary_sets) rather than ad-hoc shapes, and an unnamed weightTonnes makes a truck heavy and 80 km/h capped. These are operational distinctions the schema alone does not resolve.

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?

Opens with a specific verb+resource and scope: a route between the first and last location, via any in between, returning distance, duration and steps. It explicitly distinguishes itself from siblings by naming lookup_location as the tool for which-area-is-this questions, so an agent can route without reading 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 Guidelines5/5

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

Gives explicit when-not rules ('Not for: distance matrices, isochrones or live traffic') and names the alternative (lookup_location). It also warns against the misuse pattern of looping to compare options, and states that alternatives require exactly 2 locations.

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

list_boundary_setsList the boundary sets on this accountA
Read-only

Lists the boundary sets on this account with their boundary counts and the API keys (id and label) each is granted to. A set only matches during a lookup when it is available AND granted to the key making the call.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds behavioral context beyond annotations: it reveals the response includes boundary counts and granted API keys, and explains the availability/grants condition that affects matching. This is useful, non-redundant information.

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 with no wasted words. The first sentence front-loads the primary purpose and output content; the second adds a crucial behavioral nuance. Every word earns its place.

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

Completeness5/5

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

For a no-parameter listing tool without an output schema, the description is complete. It specifies what the response contains (boundary counts and granted API keys) and explains the matching rule, covering all an agent needs to call it correctly.

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?

The tool has zero parameters, so the baseline for parameter semantics is 4. The description does not need to explain any parameters, and it correctly focuses on behavior and output instead.

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?

The description clearly states the tool's action (Lists) and resource (boundary sets), and specifies the output includes boundary counts and the API keys (id and label) each is granted to. It distinguishes itself from siblings (create_boundary_set, add_boundary, lookup_location) by focusing on listing existing sets rather than creating or adding.

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?

The description provides context about how sets match during lookups, implying this tool is for inspecting which sets are available and granted to the calling key. However, it does not explicitly state when to use this tool versus the alternatives, such as 'use lookup_location for actual matching.' The guidance is clear but not prescriptive.

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

lookup_locationLook up the boundaries containing a coordinateA
Read-only

Reverse geocode a coordinate to the administrative areas that contain it — country, region (state or province) and municipality — as names plus ISO 3166 codes, optionally the nearest street, and matches from boundary sets the account has uploaded: all in one call.

Use for: which country, region or municipality a point is in; which street a point is on (add "street" to base); geofence checks against your own polygons; tagging data with region codes. For the other direction, an address to a coordinate, use geocode_address. For a route, a travel distance or a travel time, use get_route — 10 lookups on the standard plans to this one’s 1. Do NOT use for place search by name or for fetching boundary geometry.

Caveats worth repeating to the user: municipal is the finest unit AVAILABLE, not a consistent kind of thing — Los Angeles returns a city, rural Kansas returns a county, so do not assume it names a city. A layer that matched nothing comes back null. The errors array is always present: a boundary set that is unavailable or not granted to this key is skipped and reported there, while the call itself still succeeds.

STREETS (opt-in via base, worldwide). base.street is ALWAYS three answers, for 5 m, 20 m and unlimited in that order, each with radiusMeters, streetNumber, streetName, postcode and distanceMeters. A numbered address within the radius wins over a nearer street (for the unlimited entry the address must still be within 20 m); otherwise the nearest named street; unnamed roads never answer. Two different nulls: base.street === null means there is no street data for the point’s country, while an entry whose fields are null means nothing was within that radius — never report them the same way. streetNumber and postcode are STRINGS (44A, 12-14, 0181), house numbers are rare outside well-mapped areas. Street geometry comes back only when streetGeometry is set — leave it off unless something will draw the line.

One call is one billed lookup however many layers, sets or grid codes it touches, and a call that matches nothing still bills.

ParametersJSON Schema
NameRequiredDescriptionDefault
latYesLatitude, -90 to 90.
lngYesLongitude, -180 to 180.
baseNoWhich reference layers to resolve. Defaults to country, region and municipal. "street" is opt-in: add it explicitly to get the nearest street.
setsNoNames of the boundary sets on this account to match against. Defaults to none.
h3resNoH3 resolution 0-15. 9 is about 400 m across.
encodeNoAlso return the point as an H3 cell index and/or Google Plus Code. Output only — neither can be used AS a location, because both name areas rather than points.
pluslenNoPlus Code length. 9 is not a valid length. 10 is about 14 m.
streetGeometryNoGive each street answer the line of the street it names, trimmed to about 250 m either side of the point. Implies the street layer. Off by default, and leave it off unless something will draw it: a line is hundreds of characters nobody reads.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only declare readOnlyHint and openWorldHint, so the description carries the behavioral burden and does so richly: it discloses billing semantics (one call = one billed lookup regardless of layers, and a no-match call still bills), that the errors array is always present and reports skipped/ungranted boundary sets while the call still succeeds, and the distinction between the two kinds of null for streets. This is far beyond what the annotations supply.

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

Conciseness4/5

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

The definition is front-loaded (purpose, then Use for / alternatives, then caveats, then a dedicated STREETS section) and nearly every sentence carries information that changes agent behavior. It is dense and long, and lines like 'caveats worth repeating to the user' are slightly meta/marketing-toned, but no section is genuinely filler.

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

Completeness5/5

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

With eight parameters, no output schema, and only two required params, the description compensates thoroughly: it explains the shape of street answers, the always-present errors array, the meaning of each null variant, unit and code formats, and the billing model. An agent has everything needed to call it correctly and interpret the response without a schema.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds meaning the schema does not: base.street always returns exactly three answers (5 m, 20 m, unlimited) with named fields, streetNumber and postcode are STRINGS with examples, streetGeometry is trimmed to ~250 m and implies the street layer, and 'add street to base' is the opt-in mechanic. Null-vs-null-field semantics for street results are spelled out, which the schema cannot express.

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?

The first sentence states a specific verb (reverse geocode) plus the exact resource (administrative areas containing the coordinate) and enumerates the outputs: country, region, municipality with ISO 3166 codes, optional street, plus uploaded boundary-set matches. It also explicitly names the sibling it is not (geocode_address for the opposite direction, get_route for routes), so an agent can disambiguate without opening 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 Guidelines5/5

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

A dedicated 'Use for:' block lists the concrete tasks (country/region/municipality lookup, street identification, geofence checks against own polygons, tagging with region codes) and names the alternatives with their conditions. It adds explicit exclusions: 'Do NOT use for place search by name or for fetching boundary geometry,' and cites a cost differential versus get_route. Nothing is left to inference.

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

update_boundaryMove or reshape a boundary, keeping its name and propertiesA
DestructiveIdempotent

Replace the shape of ONE existing boundary. Its id, name, properties and set stay as they are, so every lookup that matches it keeps returning the same properties.

Use this to fix or move a zone. Do NOT delete it and add it again: that gives it a new id and loses the properties unless they are re-sent.

Name the boundary by set and name; this finds its id. If a set holds two boundaries with that name, the answer lists their ids and asks for one. The new shape gets the same checks as add_boundary, including the plan’s points-per-boundary cap (refused, unbilled). Only boundaries on this account can be changed.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNoThe boundary’s id (a UUID), when it is known. Use this or name.
setYesThe set the boundary is in.
nameNoThe boundary’s name. Use this or id.
geometryYesThe new shape: a GeoJSON Polygon.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare destructive=true, idempotent=true and openWorld=true, but the description adds value beyond them: it enumerates the preserved invariants (id, name, properties, set) and the consequence for lookups, discloses the points-per-boundary cap refusal and that refusals are unbilled, and scopes mutation to 'only boundaries on this account'. That is substantial behavioral context the annotations cannot convey.

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

Conciseness4/5

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

Front-loaded with the core action, then preservation semantics, then the anti-pattern, then resolution and validation behavior. Every sentence carries information, but the five-paragraph block is longer than strictly necessary and could be tightened without losing substance.

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

Completeness5/5

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

With no output schema, the description compensates by describing the ambiguous-name response (a list of ids and a prompt for one) and the refusal behavior for cap violations. Combined with the schema's full parameter coverage, an agent has everything needed to invoke and interpret this 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 description coverage is 100%, so the baseline is 3, but the description goes further by explaining the id/name resolution mechanism ('Name the boundary by set and name; this finds its id') and the disambiguation path when two boundaries share a name (ids listed, one requested). That adds real semantics over the schema, though it does not describe geometry coordinate constraints beyond what the schema already documents.

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 ('Replace the shape of') and a precisely scoped resource ('ONE existing boundary'), and immediately distinguishes the operation from its sibling add_boundary by contrasting with 'delete it and add it again'. An agent knows exactly what changes (geometry) and what does not (id, name, properties, set).

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

Usage Guidelines5/5

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

Gives an explicit positive case ('Use this to fix or move a zone') and an explicit anti-pattern ('Do NOT delete it and add it again') with the reason (new id, lost properties). This is a when/when-not/alternative triplet, which is the top of the scale.

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. 4 tool updatesv0.4.1
    • Addedgeocode_address
    • Addedget_route
    • Changedlookup_location1 field changed
      • addedInput schema / properties / streetGeometry
        Added value: +{
        +  "description": "Give each street answer the line of the street it names, trimmed to about 250 m either side of the point. Implies the street layer. Off by default, and leave it off unless something will draw it: a line is hundreds of characters nobody reads.",
        +  "enum": [
        +    "polyline6",
        +    "geojson"
        +  ],
        +  "type": "string"
        +}
    • Addedupdate_boundary
  2. 1 tool updatev0.1.6
    • Changedlookup_location2 fields changed
      • changedInput schema / properties / base / description
        Previous value: -"Which reference layers to resolve. Defaults to all three."New value: +"Which reference layers to resolve. Defaults to country, region and municipal. \"street\" is opt-in: add it explicitly to get the nearest street."
      • changedInput schema / properties / base / items / enum
        Previous value: -[
        -  "country",
        -  "region",
        -  "municipal"
        -]New value: +[
        +  "country",
        +  "region",
        +  "municipal",
        +  "street"
        +]
  3. 2 tool updatesv0.1.4
    • Changedadd_boundary13 fields changed
      • removedInput schema / properties / geometry / additionalProperties
        Removed value: -{}
      • changedInput schema / properties / geometry / description
        Previous value: -"GeoJSON geometry, e.g. {\"type\":\"Polygon\",\"coordinates\":[[[lng,lat],...]]}. Longitude comes first. A Feature or FeatureCollection is not accepted."New value: +"A GeoJSON Polygon, e.g. {\"type\":\"Polygon\",\"coordinates\":[[[18.40,-33.93],[18.40,-33.90],[18.44,-33.90],[18.44,-33.93],[18.40,-33.93]]]}."
      • addedInput schema / properties / geometry / properties
        Added value: +{
        +  "coordinates": {
        +    "description": "Rings of [longitude, latitude] positions. The first ring is the outline; any further rings are holes. Each ring is closed: its last position repeats its first.",
        +    "items": {
        +      "items": {
        +        "items": {
        +          "type": "number"
        +        },
        +        "maxItems": 3,
        +        "minItems": 2,
        +        "type": "array"
        +      },
        +      "minItems": 4,
        +      "type": "array"
        +    },
        +    "minItems": 1,
        +    "type": "array"
        +  },
        +  "type": {
        +    "const": "Polygon",
        +    "type": "string"
        +  }
        +}
      • removedInput schema / properties / geometry / propertyNames
        Removed value: -{
        -  "type": "string"
        -}
      • addedInput schema / properties / geometry / required
        Added value: +[
        +  "type",
        +  "coordinates"
        +]
      • changedInput schema / properties / name / description
        Previous value: -"A name for this boundary, returned on a match."New value: +"Label returned when a looked-up point falls inside this polygon, e.g. \"Zone A\"."
      • addedInput schema / properties / properties / additionalProperties / anyOf
        Added value: +[
        +  {
        +    "maxLength": 256,
        +    "type": "string"
        +  },
        +  {
        +    "type": "number"
        +  },
        +  {
        +    "type": "boolean"
        +  }
        +]
      • changedInput schema / properties / properties / description
        Previous value: -"Flat key/value pairs returned with every match of this boundary."New value: +"Optional flat key/value pairs returned with every match: keys up to 32 characters, values a string (up to 256 characters), number or boolean. The demo key accepts only category, color and priority, from fixed lists."
      • addedInput schema / properties / properties / propertyNames / maxLength
        Added value: +32
      • changedInput schema / properties / set / description
        Previous value: -"The set to add it to. It must already exist."New value: +"Name of an existing set on this account (see list_boundary_sets)."
      • removedInput schema / properties / set / maxLength
        Removed value: -32
      • removedInput schema / properties / set / minLength
        Removed value: -1
      • addedInput schema / properties / set / pattern
        Added value: +"^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$"
    • Changedcreate_boundary_set4 fields changed
      • changedInput schema / properties / name / description
        Previous value: -"A short name, used to reference the set in lookups."New value: +"A short name, used to reference the set in lookups: 1-32 letters, digits, hyphens or underscores, starting with a letter or digit."
      • removedInput schema / properties / name / maxLength
        Removed value: -32
      • removedInput schema / properties / name / minLength
        Removed value: -1
      • addedInput schema / properties / name / pattern
        Added value: +"^[a-zA-Z0-9][a-zA-Z0-9_-]{0,31}$"
  4. 4 tool updatesv0.1.2
    • First observedadd_boundary
    • First observedcreate_boundary_set
    • First observedlist_boundary_sets
    • First observedlookup_location

TDQS

A4.6/5.0

Scored across 7 tools

Disambiguation5/5

Each tool targets a distinct resource and action: forward geocoding (geocode_address), reverse geocoding (lookup_location), routing (get_route), and boundary CRUD. The descriptions go further by explicitly cross-referencing the right tool for adjacent tasks ('use geocode_address', 'use get_route'), leaving almost no room for misselection.

Naming Consistency5/5

All names follow a consistent snake_case verb_noun pattern (create_boundary_set, add_boundary, update_boundary, list_boundary_sets, lookup_location, geocode_address, get_route). The mix of domain verbs (lookup/geocode vs create/add/update/list) is predictable and readable.

Tool Count5/5

7 tools is well-scoped for a geospatial server covering forward geocoding, reverse geocoding, routing, and boundary management. Each tool earns its place with no redundancy.

Completeness4/5

Core workflows are covered across geocoding, routing, and boundary lifecycle, with out-of-scope items (batch, matrices, traffic) explicitly documented. However, boundary management lacks delete operations for boundaries or sets, and no get-single-boundary/set tool, which are minor but real gaps.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables IP address location and latitude/longitude address queries, providing detailed geographic information such as country, province, city, and district.
    2
    3 npm
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Provides forward/reverse geocoding, bounding box extraction, nearby places discovery, batch geocoding, route waypoints, and administrative boundary lookup using OpenStreetMap data.
    10
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables forward and reverse geocoding using the OpenCage API, allowing conversion between addresses and coordinates.
    11 npm
    MIT