Skip to main content
Glama

route

Compute a turn-by-turn route between origin and destination (optionally via waypoints). Costing "auto" = car, "truck" = lorry, "bicycle", "pedestrian" = walking, "motor_scooter" = moped. Pass truck {height_m, width_m, length_m, gross_weight_t, hazmat, tunnel_code} to apply dimensional limits and the ADR dangerous-goods tunnel matrix to the search; pedestrian {use_lit 0-1, type "wheelchair"|"blind", max_hiking_difficulty 1-6, use_hills 0-1, max_grade_pct 1-90, surface_quality "avoid"|"ignore"} for lit-street walking, wheelchair routing and trail limits. A wheelchair route through the MapMap gateway returns a grade block (maximum grade, ascent and descent sampled from a 30 m elevation model, the use_hills preference sent, and cap.enforced for a max_grade_pct, which the engine accepts but does not enforce yet: say so) and, where the deployment has a surface graph, a surface_quality block: applied: true means ways rated smoothness bad or worse in OpenStreetMap were avoided in the named region, a preference from ratings where they exist that says nothing about kerbs, widths, steps or inclines; applied: false gives the reason. Relay both caveats and never describe such a route as suitable for every user; bicycle {bicycle_type, use_roads 0-1, use_living_streets 0-1, avoid_bad_surfaces 0-1, use_hills 0-1} for quiet-ride and surface preferences. Returns distance (m), duration (s), maneuvers, polyline6 geometry and the ADR costing that was applied. Any of truck, auto, bicycle, pedestrian or motor_scooter routes may set rationale: true (opt-in, costs up to 1 + N extra routing calls) to learn which declared truck constraints or avoidance-side preferences (hills, surfaces, tolls, unlit streets, …) actually changed the route (rationale.avoided[], basis route_divergence, it proves a field was binding, it does not identify the physical restriction or feature, and no live traffic or incident data is ever attributed). ADR honesty: applied_adr.forbidden_tunnel_categories describes the LOAD, not the returned route, and applied_adr.tunnel_enforcement states the boundary: roads are excluded only where the routing graph records an ADR tunnel category, so an unchanged route is not a clearance. Set landmarks: true for turn instructions anchored to recognisable places, each manoeuvre that passes one gains a landmark_instruction like "Turn right just after the Shell garage" beside the engine's own street-name instruction, which is never replaced. Prefer reading it aloud: it is how a passenger gives directions. Nothing is named unless it is recognisable from the road, within 40 m of the junction and not tagged as closed, so many routes return none and a landmarks.annotated of 0 with no note means this route genuinely passes nothing recognisable. Needs the MapMap gateway (GATEWAY_URL + GATEWAY_API_KEY), whose place index does the lookup. Through the gateway each manoeuvre also carries the road it starts on: country, subdivision, ref (route numbers only), road_class, speed_limit_unit (mph or km/h, from the road's country), speed_limit_sign (vienna or mutcd), speed_limit_posted (the limit as the sign shows it, in the road's unit) and driving_side; each is absent when the map does not know it, never guessed. Optional exclude_polygons for what-if scenarios ("close this bridge and re-route"): an array of polygons, each an array of [lon, lat] pairs forming one ring (longitude FIRST) whose intersecting roads are excluded from the search. Applies to the Valhalla engine; unsupported on the GraphHopper engine, where it is ignored. Optional avoid and exclude name road features to keep off, and the difference between them is not cosmetic. avoid ("tolls", "highways", "ferries") is a PREFERENCE: it sets the costing's willingness to zero, and the engine's own reference says that is not guaranteed to avoid the feature, measured, avoiding tolls across the Dartford Crossing returns the same tolled route, because the untolled alternative is fifty kilometres further. exclude ("tolls", "highways", "ferries", "bridges", "tunnels") is a hard exclusion: it can answer NO ROUTE rather than a detour, and it depends on the routing engine's own hard-exclusion setting, which the engine does not report and this server cannot read, so it is requested, never promised. "tolls" and "highways" under avoid exist only on motorised costings; asking for one on a bicycle is refused rather than silently ignored. Whatever is applied comes back in avoidance, with the caveats, relay them, because "avoid tolls" read as a guarantee is the failure mode here. Each location also takes a kerbside approach: preferred_side "same" (alias "curb") stops on the door's side of the road, resolved against the locale's driving side, the left kerb in the UK, the right in Germany, with "opposite" and "either" (alias "unrestricted") for the rest. It is a snapping preference, not a manoeuvre guarantee, and it needs a coordinate genuinely offset from the road centreline; street_side_tolerance_m and street_side_max_distance_m bound the window in which it applies, and a pair leaving no window is refused rather than answered with the preference silently inert. Pass emissions {vehicle_category, fuel, euro_standard} for UK clean-air-zone assessment: the response's zones block then names every zone the route enters and what THIS vehicle pays there, with the publishing authority cited. Without it a zone can only be named, never priced. Needs the gateway, which holds the curated zone dataset; the whole dataset, every scheme, charge, boundary and provenance record, is readable at GET /v1/zones on the HTTP API when an agent needs to audit a figure or list zones without routing. Set scenic: true (auto costing only) to ask whether there is a prettier way. It is a PEER OFFER, never a substitution: the route in geometry_polyline6 is byte-for-byte what the same request returns without the flag, and the prettier way, when there is one, arrives beside it in scenic, with its own geometry in scenic.alternative_geometry_polyline6 and what it costs in scenic.spoken ("About seven minutes longer than the quick way"). EVERY OFFER STATES ITS REASON OR THERE IS NO OFFER: a route that scores well but cannot support a plain sentence is dropped rather than dressed up, so a scenic.reason of null means nothing here measured above the floor. That is an ANSWER, not a failure, and it is the one to relay. A REJECTION IS ALSO AN ANSWER: every candidate that lost says why in scenic.rejections[] (same_route, no_scenic_gain, not_scenic_enough, over_time_budget with the minutes it would have cost, nothing_to_say), so "no prettier way" is always attributable and raising the budget is an informed choice. It is a re-ranking of routes the engine already proposed, not a scenic search: a beautiful road the engine never offered was never considered, and scenic.caveats says so. Like rationale, IT COSTS EXTRA METERED COMPUTATIONS, at most two, which is why it is opt-in and never on by default. available: false with a note means this deployment could not look, which is not the same claim as nothing being there. Needs the gateway, whose basemap archive the scoring is measured against. Returns view_url, a mapmap.ai link that draws the answer on a map (no key needed); the link carries the stop coordinates and names.

Input Schema

NameRequiredDescriptionDefault
avoidNoRoad features to avoid as a PREFERENCE. Rendered as the costing's willingness factor set to zero, a thumb on the scale, not a ban. The engine's own reference is explicit that a value of zero is not guaranteed to avoid the feature entirely, and it does not: asking to avoid tolls across the Dartford Crossing returns the same tolled route, because the untolled alternative is fifty kilometres further. Use `exclude` when you mean a ban.
truckNoTruck profile (dimensions + ADR declaration). Requires costing "truck"; when present, ADR dangerous-goods costing options are merged into the request.
originYesRoute origin.
scenicNoAsk whether there is a prettier way (default false, `auto` costing only). The route in `geometry_polyline6` is NEVER swapped: what comes back is a peer offer beside it, in `scenic`, carrying the plain sentence that justifies it. No sentence, no offer: a route that scores well but cannot support one is dropped rather than dressed up, and `scenic.reason` is then null, which is an answer. Every candidate that lost says why in `scenic.rejections[]` (`same_route`, `no_scenic_gain`, `not_scenic_enough`, `over_time_budget`, `nothing_to_say`), so "no prettier way" is always attributable. Opt-in because it costs: at most two extra metered route computations, the same billing shape as `rationale`. Needs the MapMap gateway, whose basemap archive the scoring is measured against.
bicycleNoBicycle options (bicycle type, road/surface/hill preferences). Requires costing "bicycle".
costingNoCosting model: "auto" (default), "truck", "bicycle", "pedestrian" or "motor_scooter".auto
excludeNoRoad features to exclude outright, rendered as the costing's hard exclusion flag. Two things follow from that and both matter: a hard exclusion can return NO ROUTE rather than a detour (excluding tunnels on a Rotherhithe crossing has no answer), and the flags depend on the routing engine's `allow_hard_exclusions` setting, which the engine does not expose and nothing here can read, so this is never promised, only requested.
emissionsNoThe vehicle's emission declaration, for UK clean-air / low-emission zone assessment. Given, the response's `zones` block names every zone the route enters and what THIS vehicle pays there, with the publishing authority cited. Without it a zone can only be named, never priced. Needs the MapMap gateway, which holds the curated zone dataset; the full dataset is readable at `GET /v1/zones`.
landmarksNoName landmarks in the turn instructions (default false): each manoeuvre that passes a recognisable place, a petrol station, a supermarket, a household-name chain, gains a `landmark_instruction` like "Turn right just after the Shell garage" beside the engine's own street-name instruction, which is never replaced. Nothing is named unless it is recognisable from the road, within 40 m of the junction and not tagged as closed, so many routes come back with none: a wrong landmark is worse than no landmark. Needs the MapMap gateway, whose place index does the lookup.
rationaleNoExplain the route (default false): re-routes with each declared truck constraint (truck costing) or avoidance-side routing preference (auto, bicycle, pedestrian, motor_scooter) relaxed and reports the ones that actually changed the route as `rationale.avoided[]`. Opt-in, it costs up to 1 + N extra routing calls, one per declared field plus one combined probe, and it is billed for the ones it actually makes: at most 8 in total, typically fewer, and 1 when there is nothing to probe. Against the hosted gateway each probe is its own metered route call, which is exactly what `POST /route` with `rationale: true` charges for its own fan-out, so the two surfaces price the same explanation the same way.
waypointsNoOptional intermediate stops, visited in order between origin and destination.
pedestrianNoPedestrian options (lit-street preference, wheelchair/blind type, hiking difficulty). Requires costing "pedestrian".
destinationYesRoute destination.
exclude_polygonsNoAreas to avoid, scenario analysis ("close this bridge and re-route"): an array of polygons, each an array of `[lon, lat]` pairs forming one exterior ring (GeoJSON-style, longitude FIRST). Roads intersecting any ring are excluded from the search. Applies to the Valhalla engine; unsupported on the GraphHopper engine, where it is ignored.

Output Schema

NameRequiredDescriptionDefault
gradeNoThe hill report on a pedestrian route (only through the MapMap gateway): maximum grade, total ascent and descent sampled along the route from the elevation model, the hill preference sent, and whether a requested grade cap was enforced. Relay `cap.enforced` and the caveat as given.
zonesNoClean-air / low-emission zones this route enters and what the declared vehicle pays in each, with the publishing authority cited (only when `emissions` was declared). Passed through verbatim from the gateway's curated dataset, the same figures `GET /v1/zones` publishes, so a charge can always be audited back to its source.
scenicNoThe scenic peer offer (only when `scenic: true` was requested): whether there is a prettier way, the sentence that justifies it, what the detour costs, and why every candidate that lost lost. The route above is never swapped for it.
summaryYesOne-line human-readable summary of the route.
view_urlNoA mapmap.ai link that draws this route on a map: open it or pass it on as the last line of the answer. Nothing is stored server-side and opening it needs no key; the link itself carries the stop coordinates and stop names (plus any arrival clocks, dwell times and totals) and nothing else, so anyone holding it can read those stops. Absent when the plan cannot be linked (see `view_url_note`) or the server runs with links turned off (`SN_MCP_SITE_URL` empty).
avoidanceNoWhat `avoid`/`exclude` became, and the caveats that go with it (only when either list carried something).
landmarksNoThe landmark-annotation summary (only when `landmarks: true` was requested): how many manoeuvres gained a `landmark_instruction`, and a `note` when the per-route cap was hit or the deployment has no place index. A zero with no note means this route genuinely passes nothing recognisable.
maneuversYesOrdered turn-by-turn maneuvers across all legs.
rationaleNoWhy the route goes this way (only when `rationale: true` was requested; computed for truck, auto, bicycle, pedestrian and motor_scooter costings).
distance_mYesTotal route distance in metres.
duration_sYesTotal estimated travel time in seconds.
applied_adrNoThe ADR costing merged into the request, or null when no truck profile was given.
view_url_noteNoWhy there is no `view_url` (too many vehicles or stops for one link, or over the 6,000 character cap), or what the link left out to fit under the cap (arrival times, dwell times, then stop names). Relay it with the link.
surface_qualityNoSurface quality on a wheelchair route (only through the MapMap gateway): `applied` true with the region, the exact rule, the data timestamp and a caveat when the route was computed on the surface graph; `applied` false with a `reason` otherwise. Relay the caveat: it is a preference from OpenStreetMap ratings where they exist, and says nothing about kerbs, widths, steps or inclines.
geometry_polyline6YesFull route geometry as a Google encoded polyline with six digits of decimal precision (polyline6).

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed22 schema fields changed
    • changedInput schema / $defs / BicycleSpec / properties / use_roads / description
      Previous value: -"Willingness to ride roads alongside motor traffic, 0.0–1.0\n(0.0 = prefer cycleways and quiet streets — the quiet-ride slider)."New value: +"Willingness to ride roads alongside motor traffic, 0.0–1.0\n(0.0 = prefer cycleways and quiet streets, the quiet-ride slider)."
    • changedInput schema / $defs / EmissionsSpec / properties / euro_standard / description
      Previous value: -"Its Euro emission standard, 1–6. Heavy-duty approvals are written\nin Roman numerals (Euro VI); declare Euro VI as `6`. Required for\nany combustion fuel — without it no zone can be resolved, and a\nhalf-declared vehicle is indistinguishable from an undeclared one.\nOptional only for `electric` or `hydrogen`."New value: +"Its Euro emission standard, 1–6. Heavy-duty approvals are written\nin Roman numerals (Euro VI); declare Euro VI as `6`. Required for\nany combustion fuel, without it no zone can be resolved, and a\nhalf-declared vehicle is indistinguishable from an undeclared one.\nOptional only for `electric` or `hydrogen`."
    • changedInput schema / $defs / ExcludeFeature / description
      Previous value: -"A road feature to exclude outright. A hard exclusion can leave a request with no path at all — that is the honest answer, not a failure — and it depends on the routing engine's own hard-exclusion setting, which nothing here can read."New value: +"A road feature to exclude outright. A hard exclusion can leave a request with no path at all (that is the honest answer, not a failure) and it depends on the routing engine's own hard-exclusion setting, which nothing here can read."
    • changedInput schema / $defs / PedestrianSpec / properties / use_lit / description
      Previous value: -"Preference for lit streets, 0.0–1.0 (1.0 = prefer lit paths as\nstrongly as possible — the \"walk me home on lit streets\" option).\nUnlit ways are still used when no lit alternative exists."New value: +"Preference for lit streets, 0.0–1.0 (1.0 = prefer lit paths as\nstrongly as possible, the \"walk me home on lit streets\" option).\nUnlit ways are still used when no lit alternative exists."
    • changedInput schema / $defs / PreferredSideKind / oneOf
      Previous value: -[
      -  {
      -    "const": "same",
      -    "description": "The side the location itself projects to — the kerb, resolved\nagainst the locale's driving side (the left kerb in the UK, the\nright in Germany).",
      -    "type": "string"
      -  },
      -  {
      -    "const": "opposite",
      -    "description": "The far side of the road from the location.",
      -    "type": "string"
      -  },
      -  {
      -    "const": "either",
      -    "description": "No side preference.",
      -    "type": "string"
      -  },
      -  {
      -    "const": "curb",
      -    "description": "Alias for `same`, from the OSRM/Mapbox `approaches` vocabulary.",
      -    "type": "string"
      -  },
      -  {
      -    "const": "unrestricted",
      -    "description": "Alias for `either`, from the OSRM/Mapbox `approaches` vocabulary.",
      -    "type": "string"
      -  }
      -]New value: +[
      +  {
      +    "const": "same",
      +    "description": "The side the location itself projects to, the kerb, resolved\nagainst the locale's driving side (the left kerb in the UK, the\nright in Germany).",
      +    "type": "string"
      +  },
      +  {
      +    "const": "opposite",
      +    "description": "The far side of the road from the location.",
      +    "type": "string"
      +  },
      +  {
      +    "const": "either",
      +    "description": "No side preference.",
      +    "type": "string"
      +  },
      +  {
      +    "const": "curb",
      +    "description": "Alias for `same`, from the OSRM/Mapbox `approaches` vocabulary.",
      +    "type": "string"
      +  },
      +  {
      +    "const": "unrestricted",
      +    "description": "Alias for `either`, from the OSRM/Mapbox `approaches` vocabulary.",
      +    "type": "string"
      +  }
      +]
    • changedInput schema / $defs / RouteLocation / description
      Previous value: -"One location of a `route` request: a coordinate, plus the optional\nkerbside approach for arriving at it.\n\nA bare `{lat, lon}` is still a complete location — every kerbside field\nis optional and omitting all of them is exactly the request that was\nmade before they existed."New value: +"One location of a `route` request: a coordinate, plus the optional\nkerbside approach for arriving at it.\n\nA bare `{lat, lon}` is still a complete location, every kerbside field\nis optional and omitting all of them is exactly the request that was\nmade before they existed."
    • changedInput schema / $defs / RouteLocation / properties / preferred_side / description
      Previous value: -"Which side of the street to arrive on (or depart from). `same` (or\n`curb`) puts the vehicle on the door's side of the road, resolved\nagainst the locale's driving side. Two honest limits: this is a\n**snapping preference**, not a manoeuvre guarantee — the engine\nprefers an edge on that side, it does not promise the driver never\ncrosses — and it needs a coordinate genuinely offset from the road\ncentreline, because a point on the centreline has no side."New value: +"Which side of the street to arrive on (or depart from). `same` (or\n`curb`) puts the vehicle on the door's side of the road, resolved\nagainst the locale's driving side. Two honest limits: this is a\n**snapping preference**, not a manoeuvre guarantee, the engine\nprefers an edge on that side, it does not promise the driver never\ncrosses, and it needs a coordinate genuinely offset from the road\ncentreline, because a point on the centreline has no side."
    • changedInput schema / $defs / TruckSpec / properties / tunnel_code / description
      Previous value: -"ADR 8.6.4 tunnel restriction code of the load, e.g. \"B\", \"C5000D\",\n\"B/D\", or \"(—)\"/\"none\" for explicitly unrestricted. Leave unset if\nunknown: a hazmat load without a code is conservatively treated as\ncode B (allowed only through category-A tunnels)."New value: +"ADR 8.6.4 tunnel restriction code of the load, e.g. \"B\", \"C5000D\",\n\"B/D\", or \"(-)\"/\"none\" for explicitly unrestricted. Leave unset if\nunknown: a hazmat load without a code is conservatively treated as\ncode B (allowed only through category-A tunnels)."
    • changedInput schema / properties / avoid / description
      Previous value: -"Road features to avoid as a PREFERENCE. Rendered as the costing's\nwillingness factor set to zero — a thumb on the scale, not a ban.\nThe engine's own reference is explicit that a value of zero is not\nguaranteed to avoid the feature entirely, and it does not: asking\nto avoid tolls across the Dartford Crossing returns the same tolled\nroute, because the untolled alternative is fifty kilometres\nfurther. Use `exclude` when you mean a ban."New value: +"Road features to avoid as a PREFERENCE. Rendered as the costing's\nwillingness factor set to zero, a thumb on the scale, not a ban.\nThe engine's own reference is explicit that a value of zero is not\nguaranteed to avoid the feature entirely, and it does not: asking\nto avoid tolls across the Dartford Crossing returns the same tolled\nroute, because the untolled alternative is fifty kilometres\nfurther. Use `exclude` when you mean a ban."
    • changedInput schema / properties / exclude / description
      Previous value: -"Road features to exclude outright, rendered as the costing's hard\nexclusion flag. Two things follow from that and both matter: a hard\nexclusion can return NO ROUTE rather than a detour (excluding\ntunnels on a Rotherhithe crossing has no answer), and the flags\ndepend on the routing engine's `allow_hard_exclusions` setting,\nwhich the engine does not expose and nothing here can read — so\nthis is never promised, only requested."New value: +"Road features to exclude outright, rendered as the costing's hard\nexclusion flag. Two things follow from that and both matter: a hard\nexclusion can return NO ROUTE rather than a detour (excluding\ntunnels on a Rotherhithe crossing has no answer), and the flags\ndepend on the routing engine's `allow_hard_exclusions` setting,\nwhich the engine does not expose and nothing here can read, so\nthis is never promised, only requested."
    • changedInput schema / properties / exclude_polygons / description
      Previous value: -"Areas to avoid — scenario analysis (\"close this bridge and\nre-route\"): an array of polygons, each an array of `[lon, lat]`\npairs forming one exterior ring (GeoJSON-style, longitude FIRST).\nRoads intersecting any ring are excluded from the search. Applies\nto the Valhalla engine; unsupported on the GraphHopper engine,\nwhere it is ignored."New value: +"Areas to avoid, scenario analysis (\"close this bridge and\nre-route\"): an array of polygons, each an array of `[lon, lat]`\npairs forming one exterior ring (GeoJSON-style, longitude FIRST).\nRoads intersecting any ring are excluded from the search. Applies\nto the Valhalla engine; unsupported on the GraphHopper engine,\nwhere it is ignored."
    • changedInput schema / properties / landmarks / description
      Previous value: -"Name landmarks in the turn instructions (default false): each\nmanoeuvre that passes a recognisable place — a petrol station, a\nsupermarket, a household-name chain — gains a\n`landmark_instruction` like \"Turn right just after the Shell\ngarage\" beside the engine's own street-name instruction, which is\nnever replaced. Nothing is named unless it is recognisable from the\nroad, within 40 m of the junction and not tagged as closed, so many\nroutes come back with none: a wrong landmark is worse than no\nlandmark. Needs the MapMap gateway, whose place index does the\nlookup."New value: +"Name landmarks in the turn instructions (default false): each\nmanoeuvre that passes a recognisable place, a petrol station, a\nsupermarket, a household-name chain, gains a\n`landmark_instruction` like \"Turn right just after the Shell\ngarage\" beside the engine's own street-name instruction, which is\nnever replaced. Nothing is named unless it is recognisable from the\nroad, within 40 m of the junction and not tagged as closed, so many\nroutes come back with none: a wrong landmark is worse than no\nlandmark. Needs the MapMap gateway, whose place index does the\nlookup."
    • changedInput schema / properties / rationale / description
      Previous value: -"Explain the route (default false): re-routes with each declared\ntruck constraint (truck costing) or avoidance-side routing\npreference (auto, bicycle, pedestrian, motor_scooter) relaxed and\nreports the ones that actually changed the route as\n`rationale.avoided[]`. Opt-in — it costs up to 1 + N extra routing\ncalls, one per declared field plus one combined probe, and it is\nbilled for the ones it actually makes: at most 8 in total,\ntypically fewer, and 1 when there is nothing to probe. Against the\nhosted gateway each probe is its own metered route call, which is\nexactly what `POST /route` with `rationale: true` charges for its\nown fan-out, so the two surfaces price the same explanation the\nsame way."New value: +"Explain the route (default false): re-routes with each declared\ntruck constraint (truck costing) or avoidance-side routing\npreference (auto, bicycle, pedestrian, motor_scooter) relaxed and\nreports the ones that actually changed the route as\n`rationale.avoided[]`. Opt-in, it costs up to 1 + N extra routing\ncalls, one per declared field plus one combined probe, and it is\nbilled for the ones it actually makes: at most 8 in total,\ntypically fewer, and 1 when there is nothing to probe. Against the\nhosted gateway each probe is its own metered route call, which is\nexactly what `POST /route` with `rationale: true` charges for its\nown fan-out, so the two surfaces price the same explanation the\nsame way."
    • changedOutput schema / $defs / AppliedAdr / description
      Previous value: -"The ADR costing that was merged into a truck route request.\n\nEvery field here describes the **request**: the declared load and the\ncosting options built from it. Nothing here is an assertion about the\nreturned geometry — see [`TunnelEnforcement`]."New value: +"The ADR costing that was merged into a truck route request.\n\nEvery field here describes the **request**: the declared load and the\ncosting options built from it. Nothing here is an assertion about the\nreturned geometry, see [`TunnelEnforcement`]."
    • changedOutput schema / $defs / AppliedAdr / properties / forbidden_tunnel_categories / description
      Previous value: -"ADR tunnel categories **the vehicle** is forbidden from under the\nworst-case reading of ADR 8.6.4 (conditional clauses assumed to\napply). Empty when unrestricted. This is not a claim that the\nreturned route contains no tunnel of these categories — read\n[`AppliedAdr::tunnel_enforcement`] for what was actually applied."New value: +"ADR tunnel categories **the vehicle** is forbidden from under the\nworst-case reading of ADR 8.6.4 (conditional clauses assumed to\napply). Empty when unrestricted. This is not a claim that the\nreturned route contains no tunnel of these categories, read\n[`AppliedAdr::tunnel_enforcement`] for what was actually applied."
    • changedOutput schema / $defs / AppliedAdr / properties / tunnel_code / description
      Previous value: -"Canonical ADR tunnel restriction code applied (\"B/D\", \"(—)\", …),\nor null when no code was declared."New value: +"Canonical ADR tunnel restriction code applied (\"B/D\", \"(-)\", …),\nor null when no code was declared."
    • changedOutput schema / $defs / AppliedAvoidance / properties / costing_option_fields / description
      Previous value: -"The engine costing-option fields these words became, e.g.\n`{\"use_tolls\": 0.0, \"exclude_ferries\": true}`. This is the whole of\nwhat was sent — there is no hidden second mechanism."New value: +"The engine costing-option fields these words became, e.g.\n`{\"use_tolls\": 0.0, \"exclude_ferries\": true}`. This is the whole of\nwhat was sent, there is no hidden second mechanism."
    • changedOutput schema / $defs / AvoidedConstraint / properties / value / description
      Previous value: -"The declared value for the field (null for \"combined\"). NOTE: for\ntruck this is the vehicle's dimension, not the infrastructure\nlimit — the physical restriction is not identified."New value: +"The declared value for the field (null for \"combined\"). NOTE: for\ntruck this is the vehicle's dimension, not the infrastructure\nlimit, the physical restriction is not identified."
    • changedOutput schema / $defs / ManeuverOut / properties / landmark_instruction / description
      Previous value: -"The same manoeuvre anchored to a recognisable place, e.g. \"Turn\nright just after the Shell garage\" — present only when the request\nset `landmarks: true` and a place near the junction cleared the\nsalience bar. Prefer reading this aloud when it is there: it is how\na passenger would give the direction. `instruction` is always the\nengine's own and is never replaced."New value: +"The same manoeuvre anchored to a recognisable place, e.g. \"Turn\nright just after the Shell garage\", present only when the request\nset `landmarks: true` and a place near the junction cleared the\nsalience bar. Prefer reading this aloud when it is there: it is how\na passenger would give the direction. `instruction` is always the\nengine's own and is never replaced."
    • changedOutput schema / $defs / RouteRationale / description
      Previous value: -"Why the route goes the way it does — the `route` tool's opt-in\nrationale block, computed for truck, auto, bicycle, pedestrian and\nmotor_scooter costings. **Method honesty:** the routing engine exposes\nno exclusion set, so entries are derived by re-routing with each\ndeclared constraint or preference relaxed\n(`basis: \"route_divergence\"`); this proves a field was binding and\nwhere, but never names the physical restriction or feature (the\nspecific signed bridge, hill or unlit street). No live traffic or\nincident data enters the comparison and no delay is ever estimated\nfrom one — the engine has no live speed field."New value: +"Why the route goes the way it does, the `route` tool's opt-in\nrationale block, computed for truck, auto, bicycle, pedestrian and\nmotor_scooter costings. **Method honesty:** the routing engine exposes\nno exclusion set, so entries are derived by re-routing with each\ndeclared constraint or preference relaxed\n(`basis: \"route_divergence\"`); this proves a field was binding and\nwhere, but never names the physical restriction or feature (the\nspecific signed bridge, hill or unlit street). No live traffic or\nincident data enters the comparison and no delay is ever estimated\nfrom one, the engine has no live speed field."
    • changedOutput schema / $defs / TunnelEnforcement / description
      Previous value: -"How the declared ADR tunnel code reaches the routing engine, and what a\nreturned route therefore does — and does not — prove.\n\nThis block exists because [`AppliedAdr::forbidden_tunnel_categories`] is\na statement about the **load** (ADR 8.6.4 applied to the declared code),\nand on its own it reads like a statement about the **route**. It is not\none. The engine excludes a road only where the routing graph records an\nADR tunnel category for it, and that category is derived from OSM\n`hazmat:*` tagging. Coverage is therefore uneven: a corridor with no\nsuch tagging is not excluded and looks, in the response, exactly like a\ncorridor that was checked and cleared.\n\nThe field is emitted on every `applied_adr`, so a caller can never\nreceive the categories without the boundary that qualifies them."New value: +"How the declared ADR tunnel code reaches the routing engine, and what a\nreturned route therefore does (and does not) prove.\n\nThis block exists because [`AppliedAdr::forbidden_tunnel_categories`] is\na statement about the **load** (ADR 8.6.4 applied to the declared code),\nand on its own it reads like a statement about the **route**. It is not\none. The engine excludes a road only where the routing graph records an\nADR tunnel category for it, and that category is derived from OSM\n`hazmat:*` tagging. Coverage is therefore uneven: a corridor with no\nsuch tagging is not excluded and looks, in the response, exactly like a\ncorridor that was checked and cleared.\n\nThe field is emitted on every `applied_adr`, so a caller can never\nreceive the categories without the boundary that qualifies them."
    • changedOutput schema / properties / zones / description
      Previous value: -"Clean-air / low-emission zones this route enters and what the\ndeclared vehicle pays in each, with the publishing authority cited\n(only when `emissions` was declared). Passed through verbatim from\nthe gateway's curated dataset — the same figures `GET /v1/zones`\npublishes, so a charge can always be audited back to its source."New value: +"Clean-air / low-emission zones this route enters and what the\ndeclared vehicle pays in each, with the publishing authority cited\n(only when `emissions` was declared). Passed through verbatim from\nthe gateway's curated dataset, the same figures `GET /v1/zones`\npublishes, so a charge can always be audited back to its source."
  2. Changed2 schema fields changed
    • addedOutput schema / properties / view_url
      Added value: +{
      +  "description": "A mapmap.ai link that draws this route on a map: open it or pass it\non as the last line of the answer. Nothing is stored server-side and\nopening it needs no key; the link itself carries the stop coordinates\nand stop names (plus any arrival clocks, dwell times and totals) and\nnothing else, so anyone holding it can read those stops. Absent when\nthe plan cannot be linked (see `view_url_note`) or the server runs\nwith links turned off (`SN_MCP_SITE_URL` empty).",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / view_url_note
      Added value: +{
      +  "description": "Why there is no `view_url` (too many vehicles or stops for one link,\nor over the 6,000 character cap), or what the link left out to fit\nunder the cap (arrival times, dwell times, then stop names). Relay it\nwith the link.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
  3. Changed7 schema fields changed
    • changedInput schema / $defs / PedestrianSpec / description
      Previous value: -"Pedestrian options for costing \"pedestrian\": lit-street preference,\naccessibility type and hiking difficulty, mapped onto Valhalla\n`costing_options.pedestrian`. All preferences, never guarantees — the\nrouter prefers matching ways where the map data supports it."New value: +"Pedestrian options for costing \"pedestrian\": lit-street preference,\npedestrian type, hills, surface quality and hiking difficulty, mapped\nonto Valhalla `costing_options.pedestrian` (surface quality and the\ngrade cap are MapMap gateway fields). All preferences, never\nguarantees: the router prefers matching ways where the map data\nsupports it."
    • addedInput schema / $defs / PedestrianSpec / properties / max_grade_pct
      Added value: +{
      +  "description": "Maximum grade in whole percent, 1–90. Needs the MapMap gateway:\nthe routing engine accepts this cap but does not enforce it yet,\nand the gateway's `grade.cap` says so on every route that sets it.",
      +  "format": "uint32",
      +  "minimum": 0,
      +  "type": [
      +    "integer",
      +    "null"
      +  ]
      +}
    • addedInput schema / $defs / PedestrianSpec / properties / surface_quality
      Added value: +{
      +  "description": "Surface quality for wheelchair routes: \"avoid\" (the default where\nthe deployment has a surface graph covering the route) or \"ignore\"\n(use the ordinary graph). Wheelchair only, and needs the MapMap\ngateway; the `surface_quality` block in the output says whether it\nwas applied.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • changedInput schema / $defs / PedestrianSpec / properties / type / description
      Previous value: -"Pedestrian type: \"wheelchair\" (avoids steps, kerbs and steep\ngrades where mapped) or \"blind\" (richer guidance detail). Omit for\nthe default on-foot profile."New value: +"Pedestrian type: \"wheelchair\" (avoids mapped steps and kerbs and\nthe rougher surface classes; hills per `use_hills`) or \"blind\"\n(richer guidance detail). Omit for the default on-foot profile."
    • addedInput schema / $defs / PedestrianSpec / properties / use_hills
      Added value: +{
      +  "description": "Willingness to take hills, 0.0–1.0 (0.0 = avoid climbs as strongly\nas the engine can; the engine default is 0.5). A preference, not a\ncap. The MapMap gateway sends 0.0 on a wheelchair route that does\nnot set it, and reports that in `grade.preference`.",
      +  "format": "double",
      +  "type": [
      +    "number",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / grade
      Added value: +{
      +  "description": "The hill report on a pedestrian route (only through the MapMap\ngateway): maximum grade, total ascent and descent sampled along\nthe route from the elevation model, the hill preference sent, and\nwhether a requested grade cap was enforced. Relay `cap.enforced`\nand the caveat as given."
      +}
    • addedOutput schema / properties / surface_quality
      Added value: +{
      +  "description": "Surface quality on a wheelchair route (only through the MapMap\ngateway): `applied` true with the region, the exact rule, the data\ntimestamp and a caveat when the route was computed on the surface\ngraph; `applied` false with a `reason` otherwise. Relay the caveat:\nit is a preference from OpenStreetMap ratings where they exist,\nand says nothing about kerbs, widths, steps or inclines."
      +}
  4. Changed8 schema fields changed
    • addedOutput schema / $defs / ManeuverOut / properties / country
      Added value: +{
      +  "description": "ISO 3166-1 alpha-2 country of the road the manoeuvre starts on, e.g.\n`\"GB\"`. This and the road fields below come from the MapMap gateway's\nroad walk: present when the route was computed through the gateway\n(GATEWAY_URL + GATEWAY_API_KEY) and the map knows the road, absent\notherwise. Never inferred.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / driving_side
      Added value: +{
      +  "description": "The side of the road traffic keeps to there, `\"left\"` or `\"right\"`;\npresent only when the road's country is known.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / ref
      Added value: +{
      +  "description": "Route numbers of that road (`\"; \"` separated, e.g. `\"A27\"` or\n`\"I 5; US 101\"`); absent when it carries none, never read from a\nstreet name.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / road_class
      Added value: +{
      +  "description": "Engine road class of that road (`motorway`, `trunk`, `primary`,\n`secondary`, `tertiary`, `unclassified`, `residential`,\n`service_other`).",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / speed_limit_posted
      Added value: +{
      +  "description": "The posted limit as the sign shows it, in the road's own unit:\n`{\"type\":\"known\",\"value\":30,\"unit\":\"mph\"}` (plus `\"national\":true`\nfor a national limit), `{\"type\":\"unlimited\"}` or `{\"type\":\"unknown\"}`.\nRead from the road the manoeuvre mostly travels along."
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / speed_limit_sign
      Added value: +{
      +  "description": "The speed-limit sign family there: `\"vienna\"` (roundel) or\n`\"mutcd\"` (US and Canadian rectangle).",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / speed_limit_unit
      Added value: +{
      +  "description": "The unit speed limits are posted in on that road, `\"mph\"` or\n`\"km/h\"`, from its country (never from the request's units).",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ManeuverOut / properties / subdivision
      Added value: +{
      +  "description": "ISO 3166-2 subdivision of that road where the map carries one, e.g.\n`\"GB-ENG\"` or `\"US-CA\"`.",
      +  "type": [
      +    "string",
      +    "null"
      +  ]
      +}
  5. Changed9 schema fields changed
    • addedInput schema / $defs / RouteLocation / anyOf
      Added value: +[
      +  {
      +    "properties": {
      +      "lat": {
      +        "description": "Latitude in decimal degrees (−90 to 90).",
      +        "format": "double",
      +        "type": "number"
      +      },
      +      "lon": {
      +        "description": "Longitude in decimal degrees (−180 to 180).",
      +        "format": "double",
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "lat",
      +      "lon"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "description": "GeoJSON position [lon, lat]: longitude FIRST.",
      +    "items": {
      +      "format": "double",
      +      "type": "number"
      +    },
      +    "maxItems": 2,
      +    "minItems": 2,
      +    "type": "array"
      +  }
      +]
    • removedInput schema / $defs / RouteLocation / properties / lat
      Removed value: -{
      -  "description": "Latitude in decimal degrees (−90 to 90).",
      -  "format": "double",
      -  "type": "number"
      -}
    • removedInput schema / $defs / RouteLocation / properties / lon
      Removed value: -{
      -  "description": "Longitude in decimal degrees (−180 to 180).",
      -  "format": "double",
      -  "type": "number"
      -}
    • removedInput schema / $defs / RouteLocation / required
      Removed value: -[
      -  "lat",
      -  "lon"
      -]
    • addedOutput schema / $defs / LatLon / anyOf
      Added value: +[
      +  {
      +    "properties": {
      +      "lat": {
      +        "description": "Latitude in decimal degrees (−90 to 90).",
      +        "format": "double",
      +        "type": "number"
      +      },
      +      "lon": {
      +        "description": "Longitude in decimal degrees (−180 to 180).",
      +        "format": "double",
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "lat",
      +      "lon"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "description": "GeoJSON position [lon, lat]: longitude FIRST.",
      +    "items": {
      +      "format": "double",
      +      "type": "number"
      +    },
      +    "maxItems": 2,
      +    "minItems": 2,
      +    "type": "array"
      +  }
      +]
    • changedOutput schema / $defs / LatLon / description
      Previous value: -"A WGS84 coordinate pair in decimal degrees."New value: +"A WGS84 coordinate in decimal degrees: a {lat, lon} object (preferred), or a GeoJSON [lon, lat] array with LONGITUDE FIRST, the same order as every polygon field on this server."
    • removedOutput schema / $defs / LatLon / properties
      Removed value: -{
      -  "lat": {
      -    "description": "Latitude in decimal degrees (−90 to 90).",
      -    "format": "double",
      -    "type": "number"
      -  },
      -  "lon": {
      -    "description": "Longitude in decimal degrees (−180 to 180).",
      -    "format": "double",
      -    "type": "number"
      -  }
      -}
    • removedOutput schema / $defs / LatLon / required
      Removed value: -[
      -  "lat",
      -  "lon"
      -]
    • removedOutput schema / $defs / LatLon / type
      Removed value: -"object"
  6. Changed4 schema fields changed
    • addedInput schema / properties / scenic
      Added value: +{
      +  "description": "Ask whether there is a prettier way (default false, `auto`\ncosting only). The route in `geometry_polyline6` is NEVER swapped:\nwhat comes back is a peer offer beside it, in `scenic`, carrying\nthe plain sentence that justifies it. No sentence, no offer: a\nroute that scores well but cannot support one is dropped rather\nthan dressed up, and `scenic.reason` is then null, which is an\nanswer. Every candidate that lost says why in\n`scenic.rejections[]` (`same_route`, `no_scenic_gain`,\n`not_scenic_enough`, `over_time_budget`, `nothing_to_say`), so\n\"no prettier way\" is always attributable. Opt-in because it\ncosts: at most two extra metered route computations, the same\nbilling shape as `rationale`. Needs the MapMap gateway, whose\nbasemap archive the scoring is measured against.",
      +  "type": [
      +    "boolean",
      +    "null"
      +  ]
      +}
    • addedOutput schema / $defs / ScenicOffer
      Added value: +{
      +  "description": "The scenic assessment beside a route: a peer offer, never a\nsubstitution.\n\nThe fields here are the ones a client must actually read before\nsaying anything. `block` keeps the gateway's whole answer beside them\nso a figure can always be audited back to the source that produced\nit, rather than to this mapping.",
      +  "properties": {
      +    "alternative_geometry_polyline6": {
      +      "description": "The scenic route's own geometry, polyline6, when there is one to\noffer. `geometry_polyline6` on the route itself is byte-for-byte\nwhat the same request returns without the flag.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "available": {
      +      "description": "Whether scenery could be assessed at all on this deployment. When\nfalse, `note` says why and nothing below was measured: that is\n\"we could not look\", never \"there is nothing there\".",
      +      "type": "boolean"
      +    },
      +    "block": {
      +      "description": "The gateway's whole `scenic` block, verbatim: candidates, feature\nshares, tile coverage, metering and budget."
      +    },
      +    "caveats": {
      +      "description": "The standing limits of the method, for relaying to users.",
      +      "type": "string"
      +    },
      +    "chosen": {
      +      "description": "Which route the assessment would offer: `\"fastest\"` (the quick way\nis already the pretty one, or nothing beat it) or `\"scenic\"`.",
      +      "type": "string"
      +    },
      +    "extra_time_s": {
      +      "description": "How much longer the offered route takes than the fastest one,\nseconds, and the sentence for it. Absent when nothing was offered.",
      +      "format": "double",
      +      "type": [
      +        "number",
      +        "null"
      +      ]
      +    },
      +    "note": {
      +      "description": "Why no assessment ran (only when `available` is false).",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "reason": {
      +      "description": "The plain, speakable sentence behind the offer. **Null is an\nanswer**: nothing on this corridor measured above the floor, so\nno claim is made rather than one being invented.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "rejections": {
      +      "description": "Why each candidate that lost lost. Empty when none did. Relay it:\nit is what makes \"no prettier way\" an attributable answer instead\nof a shrug.",
      +      "items": {
      +        "$ref": "#/$defs/ScenicRejection"
      +      },
      +      "type": "array"
      +    },
      +    "spoken": {
      +      "description": "The trade phrased for speech, e.g. \"About seven minutes longer\nthan the quick way.\" Prefer reading this aloud over the seconds.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "available",
      +    "chosen",
      +    "caveats",
      +    "block"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / $defs / ScenicRejection
      Added value: +{
      +  "description": "Why one candidate route was not offered.",
      +  "properties": {
      +    "code": {
      +      "description": "The rejection code: `same_route`, `no_scenic_gain`,\n`not_scenic_enough`, `over_time_budget` or `nothing_to_say`.",
      +      "type": "string"
      +    },
      +    "detail": {
      +      "description": "The code in words, including the minutes an `over_time_budget`\ncandidate would have cost, so raising the budget is an informed\nchoice rather than a guess.",
      +      "type": "string"
      +    },
      +    "source": {
      +      "description": "Where the candidate came from: `\"fastest\"`, `\"engine_alternate\"`\nor `\"no_motorway\"`.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "source",
      +    "code",
      +    "detail"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / properties / scenic
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/ScenicOffer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "The scenic peer offer (only when `scenic: true` was requested):\nwhether there is a prettier way, the sentence that justifies it,\nwhat the detour costs, and why every candidate that lost lost.\nThe route above is never swapped for it."
      +}
  7. Changed17 schema fields changed
    • addedInput schema / $defs / AvoidFeature
      Added value: +{
      +  "description": "A road feature to avoid as a PREFERENCE, not a ban. \"tolls\" and \"highways\" apply to motorised costings only (auto, truck, bus, motor_scooter, motorcycle); \"ferries\" applies to every costing. Asking for one on a costing whose engine table has no field for it is refused rather than silently ignored.",
      +  "enum": [
      +    "tolls",
      +    "highways",
      +    "ferries"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / $defs / EmissionsFuel
      Added value: +{
      +  "description": "What a vehicle burns, in clean-air-zone scheme terms.",
      +  "oneOf": [
      +    {
      +      "const": "petrol",
      +      "description": "Petrol, including petrol hybrids (schemes rate a hybrid by its\ncombustion engine's approval).",
      +      "type": "string"
      +    },
      +    {
      +      "const": "diesel",
      +      "description": "Diesel, including diesel hybrids.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "electric",
      +      "description": "Battery-electric.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "hydrogen",
      +      "description": "Hydrogen fuel cell.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "gas",
      +      "description": "LPG or CNG; rated as petrol by every scheme in the dataset.",
      +      "type": "string"
      +    }
      +  ]
      +}
    • addedInput schema / $defs / EmissionsSpec
      Added value: +{
      +  "description": "A vehicle's emission declaration, for clean-air / low-emission zone\nassessment.",
      +  "properties": {
      +    "euro_standard": {
      +      "description": "Its Euro emission standard, 1–6. Heavy-duty approvals are written\nin Roman numerals (Euro VI); declare Euro VI as `6`. Required for\nany combustion fuel — without it no zone can be resolved, and a\nhalf-declared vehicle is indistinguishable from an undeclared one.\nOptional only for `electric` or `hydrogen`.",
      +      "format": "uint8",
      +      "maximum": 255,
      +      "minimum": 0,
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    },
      +    "fuel": {
      +      "$ref": "#/$defs/EmissionsFuel",
      +      "description": "What it burns."
      +    },
      +    "vehicle_category": {
      +      "$ref": "#/$defs/EmissionsVehicleCategory",
      +      "description": "What kind of vehicle this is, in scheme terms."
      +    }
      +  },
      +  "required": [
      +    "vehicle_category",
      +    "fuel"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / $defs / EmissionsVehicleCategory
      Added value: +{
      +  "description": "What a vehicle is, in clean-air-zone scheme terms.\n\nDeclaring this turns \"charge depends on vehicle emissions\" into an\nanswer. Without it a zone can only be named, never priced.",
      +  "oneOf": [
      +    {
      +      "const": "car",
      +      "description": "A private car.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "van",
      +      "description": "A van or light goods vehicle up to 3.5 tonnes.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "minibus",
      +      "description": "A minibus (typically 8+ passenger seats, up to 5 tonnes).",
      +      "type": "string"
      +    },
      +    {
      +      "const": "hgv",
      +      "description": "A heavy goods vehicle over 3.5 tonnes.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "bus",
      +      "description": "A bus over 5 tonnes.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "coach",
      +      "description": "A coach over 5 tonnes.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "taxi",
      +      "description": "A licensed hackney carriage.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "phv",
      +      "description": "A private hire vehicle.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "motorcycle",
      +      "description": "A motorcycle, moped or tricycle.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "motorhome",
      +      "description": "A motor caravan or campervan.",
      +      "type": "string"
      +    }
      +  ]
      +}
    • addedInput schema / $defs / ExcludeFeature
      Added value: +{
      +  "description": "A road feature to exclude outright. A hard exclusion can leave a request with no path at all — that is the honest answer, not a failure — and it depends on the routing engine's own hard-exclusion setting, which nothing here can read.",
      +  "enum": [
      +    "tolls",
      +    "highways",
      +    "ferries",
      +    "bridges",
      +    "tunnels"
      +  ],
      +  "type": "string"
      +}
    • removedInput schema / $defs / LatLon
      Removed value: -{
      -  "description": "A WGS84 coordinate pair in decimal degrees.",
      -  "properties": {
      -    "lat": {
      -      "description": "Latitude in decimal degrees (−90 to 90).",
      -      "format": "double",
      -      "type": "number"
      -    },
      -    "lon": {
      -      "description": "Longitude in decimal degrees (−180 to 180).",
      -      "format": "double",
      -      "type": "number"
      -    }
      -  },
      -  "required": [
      -    "lat",
      -    "lon"
      -  ],
      -  "type": "object"
      -}
    • addedInput schema / $defs / PreferredSideKind
      Added value: +{
      +  "description": "Side-of-street preference for arriving at or departing from a location.\n\nCarries both vocabularies: MapMap's own `same`/`opposite`/`either` and\nthe OSRM/Mapbox `approaches` words `curb`/`unrestricted`, which are\naliases for `same` and `either`. Both spell the same request, on this\nsurface and on the HTTP API.",
      +  "oneOf": [
      +    {
      +      "const": "same",
      +      "description": "The side the location itself projects to — the kerb, resolved\nagainst the locale's driving side (the left kerb in the UK, the\nright in Germany).",
      +      "type": "string"
      +    },
      +    {
      +      "const": "opposite",
      +      "description": "The far side of the road from the location.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "either",
      +      "description": "No side preference.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "curb",
      +      "description": "Alias for `same`, from the OSRM/Mapbox `approaches` vocabulary.",
      +      "type": "string"
      +    },
      +    {
      +      "const": "unrestricted",
      +      "description": "Alias for `either`, from the OSRM/Mapbox `approaches` vocabulary.",
      +      "type": "string"
      +    }
      +  ]
      +}
    • addedInput schema / $defs / RouteLocation
      Added value: +{
      +  "description": "One location of a `route` request: a coordinate, plus the optional\nkerbside approach for arriving at it.\n\nA bare `{lat, lon}` is still a complete location — every kerbside field\nis optional and omitting all of them is exactly the request that was\nmade before they existed.",
      +  "properties": {
      +    "lat": {
      +      "description": "Latitude in decimal degrees (−90 to 90).",
      +      "format": "double",
      +      "type": "number"
      +    },
      +    "lon": {
      +      "description": "Longitude in decimal degrees (−180 to 180).",
      +      "format": "double",
      +      "type": "number"
      +    },
      +    "preferred_side": {
      +      "anyOf": [
      +        {
      +          "$ref": "#/$defs/PreferredSideKind"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Which side of the street to arrive on (or depart from). `same` (or\n`curb`) puts the vehicle on the door's side of the road, resolved\nagainst the locale's driving side. Two honest limits: this is a\n**snapping preference**, not a manoeuvre guarantee — the engine\nprefers an edge on that side, it does not promise the driver never\ncrosses — and it needs a coordinate genuinely offset from the road\ncentreline, because a point on the centreline has no side."
      +    },
      +    "street_side_max_distance_m": {
      +      "description": "Metres: further than this from the road centreline, the side of\nstreet is treated as `none` and `preferred_side` does nothing.\nEngine default 1000 m. Together with `street_side_tolerance_m` this\nis a WINDOW: a pair that leaves no window (tolerance at or above\nmax distance) is refused here rather than answered with a route on\nwhich the kerbside preference was silently inert.",
      +      "format": "uint32",
      +      "minimum": 0,
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    },
      +    "street_side_tolerance_m": {
      +      "description": "Metres: nearer than this to the road centreline, the side of street\nis treated as `none` and `preferred_side` does nothing. Engine\ndefault 5 m.",
      +      "format": "uint32",
      +      "minimum": 0,
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "lat",
      +    "lon"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / avoid
      Added value: +{
      +  "description": "Road features to avoid as a PREFERENCE. Rendered as the costing's\nwillingness factor set to zero — a thumb on the scale, not a ban.\nThe engine's own reference is explicit that a value of zero is not\nguaranteed to avoid the feature entirely, and it does not: asking\nto avoid tolls across the Dartford Crossing returns the same tolled\nroute, because the untolled alternative is fifty kilometres\nfurther. Use `exclude` when you mean a ban.",
      +  "items": {
      +    "$ref": "#/$defs/AvoidFeature"
      +  },
      +  "type": [
      +    "array",
      +    "null"
      +  ]
      +}
    • changedInput schema / properties / destination / $ref
      Previous value: -"#/$defs/LatLon"New value: +"#/$defs/RouteLocation"
    • addedInput schema / properties / emissions
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/EmissionsSpec"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "The vehicle's emission declaration, for UK clean-air / low-emission\nzone assessment. Given, the response's `zones` block names every\nzone the route enters and what THIS vehicle pays there, with the\npublishing authority cited. Without it a zone can only be named,\nnever priced. Needs the MapMap gateway, which holds the curated\nzone dataset; the full dataset is readable at `GET /v1/zones`."
      +}
    • addedInput schema / properties / exclude
      Added value: +{
      +  "description": "Road features to exclude outright, rendered as the costing's hard\nexclusion flag. Two things follow from that and both matter: a hard\nexclusion can return NO ROUTE rather than a detour (excluding\ntunnels on a Rotherhithe crossing has no answer), and the flags\ndepend on the routing engine's `allow_hard_exclusions` setting,\nwhich the engine does not expose and nothing here can read — so\nthis is never promised, only requested.",
      +  "items": {
      +    "$ref": "#/$defs/ExcludeFeature"
      +  },
      +  "type": [
      +    "array",
      +    "null"
      +  ]
      +}
    • changedInput schema / properties / origin / $ref
      Previous value: -"#/$defs/LatLon"New value: +"#/$defs/RouteLocation"
    • changedInput schema / properties / waypoints / items / $ref
      Previous value: -"#/$defs/LatLon"New value: +"#/$defs/RouteLocation"
    • addedOutput schema / $defs / AppliedAvoidance
      Added value: +{
      +  "description": "What the avoidance lists actually did, reported back so a 200 is never\nreadable as a certificate.",
      +  "properties": {
      +    "avoid": {
      +      "description": "The `avoid` values that were applied, echoed back.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "caveats": {
      +      "description": "The caveats that apply to this request, in words fit to repeat to a\nuser. Always present when anything was applied.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "costing_option_fields": {
      +      "description": "The engine costing-option fields these words became, e.g.\n`{\"use_tolls\": 0.0, \"exclude_ferries\": true}`. This is the whole of\nwhat was sent — there is no hidden second mechanism."
      +    },
      +    "exclude": {
      +      "description": "The `exclude` values that were applied, echoed back.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "costing_option_fields",
      +    "caveats"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / properties / avoidance
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/AppliedAvoidance"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "What `avoid`/`exclude` became, and the caveats that go with it\n(only when either list carried something)."
      +}
    • addedOutput schema / properties / zones
      Added value: +{
      +  "description": "Clean-air / low-emission zones this route enters and what the\ndeclared vehicle pays in each, with the publishing authority cited\n(only when `emissions` was declared). Passed through verbatim from\nthe gateway's curated dataset — the same figures `GET /v1/zones`\npublishes, so a charge can always be audited back to its source."
      +}
  8. First observed

TDQS

A4.1/5.0
Behavior5/5

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

With no annotations, the description carries the full behavioral burden and does so thoroughly: it distinguishes preference (`avoid`) from hard exclusion (`exclude`) including the Dartford Crossing and Rotherhithe examples, discloses that `max_grade_pct` is accepted but not enforced, that exclusion depends on an unreadable `allow_hard_exclusions` flag, that gateway credentials are required for several features, and the metered cost of `rationale` and `scenic`. Refusal behaviors (no window, unsupported avoid features) and no-route outcomes are also disclosed.

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

Conciseness2/5

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

The purpose is front-loaded, but the body is an extremely long, densely parenthetical wall of text that frequently duplicates content already present in the 100%-covered schema and the output schema (e.g. the kerbside window, ADR honesty, scenic rejection codes are all restated). For a 14-parameter call the agent must wade through far more prose than the decision requires, so size and redundancy drag this down.

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 complex multi-costing routing tool with no annotations, the description covers everything an agent needs: engine/gateway dependencies, engine-specific limitations, cost of opt-in flags, honesty caveats, and what several response blocks mean. With an output schema present it need not explain return values, yet nothing essential 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 the baseline is 3, but the description adds genuine meaning beyond the schema: it explains why `avoid` and `exclude` differ behaviourally, what the kerbside preference actually resolves against, that `exclude_polygons` is ignored on GraphHopper, and what `emissions` unlocks. These are semantic distinctions the schema fields alone do not convey.

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 opening sentence gives a specific verb and resource: "Compute a turn-by-turn route between origin and destination (optionally via waypoints)." It tells the agent exactly what comes back and the origin/destination/waypoint shape. It does not, however, differentiate itself from routing-adjacent siblings like optimise_routes, matrix, replan_routes or reachable_area, so the agent must infer when this tool rather than another is correct.

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?

There is extensive conditional guidance for the optional features: "Use `exclude` when you mean a ban", avoid applies only to motorised costings, scenic is auto-only, exclude_polygons is Valhalla-only, emissions is needed to price rather than merely name a zone. That is strong when-to-use guidance at the parameter level. It gives no guidance on selecting this tool over sibling routing tools, which is the one gap.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources