Skip to main content
Glama

optimise_routes

Optimise multi-vehicle, multi-stop delivery plans (VRP). Provide vehicles (id, start/end, capacity, skills, time_window), jobs (id, location, service_s, delivery/pickup, skills, time_windows) and/or shipments (pickup+delivery pairs that ride the same vehicle). Costing "auto", "truck", "bicycle", "pedestrian" or "motor_scooter" (cargo-bike and courier fleets welcome): with a truck profile (dimensions + ADR declaration, as in route), the travel-time matrix respects dimensional and dangerous-goods restrictions, so every optimised route is truck-legal. Returns a summary, unassigned tasks and per-vehicle routes with ordered steps (arrival_s/duration_s in seconds, distance_m in metres). Fair use: at most 200 unique locations per problem, and no wider than the routing engine's matrix span (1,500 km on the hosted endpoint for motor costings, 400 km stock on a self-host). Past that, cluster the stops with cluster and optimise each group, or submit the whole problem to the asynchronous lane with submit_optimise_job (2,000 locations). Optional territories are named polygons ([{id, polygon}], GeoJSON [lon, lat] rings, LONGITUDE FIRST) that bound who serves what: a vehicle listing territory_ids may serve a task only if that task sits inside at least one of the territories it names, while a vehicle listing none is unrestricted and may serve anything, inside a round or outside every one. The response's territories block says which vehicle was eligible for what and names any task no vehicle could take. A vehicle may also declare reloads {max_trips 2-5, reload_time_s, depot?} to return to a depot, reload and go out again, the tipping round. It needs a time_window, because the shift is what gets split: it is cut into that many consecutive non-overlapping windows separated by the reload time, each trip carrying the vehicle's FULL capacity and task caps. That split is fixed BEFORE the solve, so the plan is conservative and never optimistic, it cannot put a lorry in two places at once, but it is an approximation: a trip that finishes early cannot lend its spare time to the next, so stops can come back unassigned that a truly sequential model would have served, and max_trips is a budget rather than a prediction (ask for five on a shift that supports three and every window shrinks to a fifth). Read the returned reloads block before quoting arrival times, and re-plan after each tip with replan_routes for the tighter answer. relax_if_unassigned {time_windows_by_s?, allow_overtime_s?} re-solves ONCE with those relaxations if the first plan left work unassigned, and the relaxation block says honestly which plan came back: at most one second solve, never beyond the caps stated, and the relaxed plan is returned ONLY if it assigns more work than the first. Breaks are never widened, a driver's rest is not a preference to trade for a fuller van , and neither are capacities, skills, territories or task caps; only time windows move. It bills as two solves when the second one runs. Always check relaxation.relaxed_plan_used before telling anyone the day fits: a plan produced under relaxation has had promises moved. emissions {vehicle_category, fuel, euro_standard} annotates the plan with the clean-air zones its own stops sit in and what this vehicle pays in each; add avoid_zones: true to steer the travel-time matrix out of them, which changes the plan itself. Territories, reloads, relaxation and zones are computed by the MapMap gateway; without one configured the tool refuses rather than returning a plan that quietly ignored them. 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
jobsNoSingle-stop jobs (at least one job or shipment overall).
truckNoTruck profile (dimensions + ADR declaration). Requires costing "truck"; the travel-time matrix then respects dimensional and dangerous-goods restrictions, so the whole plan is truck-legal.
costingNoCosting model for the travel-time matrix: "auto" (default), "truck", "bicycle", "pedestrian" or "motor_scooter".auto
vehiclesYesThe fleet (at least one vehicle, each with a start and/or end).
emissionsNoThe fleet's emission declaration, for UK clean-air / low-emission zone assessment. On its own it annotates: the response's `zones` block names every zone containing one of the problem's own locations and what this vehicle would pay there. With `avoid_zones` it also steers the internal travel-time matrix away from those zones, so the plan itself changes.
shipmentsNoPickup+delivery pairs.
avoid_zonesNoKeep the optimisation's travel-time matrix out of every zone the declared vehicle would be charged or banned in. Requires `emissions`.
territoriesNoFleet territories: named polygons that bound which vehicle may serve which stop, referenced by `vehicles[].territory_ids`. These are request data, caller-drawn rounds, validated per call and never stored. Nothing to do with clean-air zones or with the offline map packages of the same word.
relax_if_unassignedNoRe-solve ONCE with these relaxations if the first solve leaves work unassigned, and say honestly which plan came back. At most one second solve, never beyond the caps you state, and the relaxed plan is returned only if it assigns MORE work than the first, giving away constraints for nothing is strictly worse than not giving them away. Breaks are never widened, nor are capacities, skills, territories or task caps: only time windows move, and only by the stated amounts. Bills as two solves when the second one runs.

Output Schema

NameRequiredDescriptionDefault
zonesNoClean-air / low-emission zones touching the problem's own locations, and what the declared vehicle pays in each. Present only when `emissions` was declared.
routesYesOne optimised route per used vehicle.
profileYesThe matrix costing profile the plan was computed with ("auto", "truck", "bicycle", "pedestrian" or "motor_scooter").
reloadsNoThe multi-trip split: each vehicle's trips, their windows, the depot each returns to, and the stated approximation. Present only when a vehicle declared `reloads`. Read the `basis` inside it before quoting arrival times. The trip windows are fixed BEFORE the solve, so a lorry that tips early cannot lend the spare time to its next trip: stops can come back unassigned that a truly sequential model would have served. The plan is feasible, never optimistic, it cannot put a vehicle in two places at once, but it is not optimal. Re-plan after each tip through `replan_routes` for the tighter answer.
summaryYesSolution summary.
view_urlNoA mapmap.ai link that draws this fleet plan, one route per vehicle, 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).
relaxationNoThe relaxation report: the caps requested, whether a second solve ran, whether ITS plan is the one returned, what was widened, and what is still unassigned. Present only when `relax_if_unassigned` was declared. Always read `second_solve` and `relaxed_plan_used` before telling anyone the day fits. A plan produced under relaxation has had promises moved, and the block is what says so.
unassignedYesTasks the solver could not assign to any vehicle.
territoriesNoHow the territories bound the plan: which vehicle was eligible for what, and any task no eligible vehicle existed for. Present only when `territories` was declared.
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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed9 schema fields changed
    • 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 / OptimiseVehicleSpec / properties / reloads / description
      Previous value: -"Let this vehicle return to a depot, reload and go out again — the\nwaste-collection tipping round, the van that comes back for a\nsecond wave of parcels."New value: +"Let this vehicle return to a depot, reload and go out again, the\nwaste-collection tipping round, the van that comes back for a\nsecond wave of parcels."
    • changedInput schema / $defs / RelaxSpec / properties / allow_overtime_s / description
      Previous value: -"Extend every vehicle's shift END by this many seconds. Shift starts\nare never moved earlier — a driver cannot begin before they begin."New value: +"Extend every vehicle's shift END by this many seconds. Shift starts\nare never moved earlier, a driver cannot begin before they begin."
    • changedInput schema / $defs / ReloadsSpec / properties / reload_time_s / description
      Previous value: -"Seconds at the depot between trips — tipping, reloading, the\nweighbridge. Held out of the shift before it is partitioned, so it\nis never accidentally spent driving."New value: +"Seconds at the depot between trips, tipping, reloading, the\nweighbridge. Held out of the shift before it is partitioned, so it\nis never accidentally spent driving."
    • changedInput schema / $defs / TerritorySpec / properties / polygon / description
      Previous value: -"The outer ring as GeoJSON `[lon, lat]` positions — longitude\nFIRST. Closed or open; an unclosed ring is closed for you."New value: +"The outer ring as GeoJSON `[lon, lat]` positions, longitude\nFIRST. Closed or open; an unclosed ring is closed for you."
    • 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 / relax_if_unassigned / description
      Previous value: -"Re-solve ONCE with these relaxations if the first solve leaves work\nunassigned, and say honestly which plan came back. At most one\nsecond solve, never beyond the caps you state, and the relaxed plan\nis returned only if it assigns MORE work than the first — giving\naway constraints for nothing is strictly worse than not giving them\naway. Breaks are never widened, nor are capacities, skills,\nterritories or task caps: only time windows move, and only by the\nstated amounts. Bills as two solves when the second one runs."New value: +"Re-solve ONCE with these relaxations if the first solve leaves work\nunassigned, and say honestly which plan came back. At most one\nsecond solve, never beyond the caps you state, and the relaxed plan\nis returned only if it assigns MORE work than the first, giving\naway constraints for nothing is strictly worse than not giving them\naway. Breaks are never widened, nor are capacities, skills,\nterritories or task caps: only time windows move, and only by the\nstated amounts. Bills as two solves when the second one runs."
    • changedInput schema / properties / territories / description
      Previous value: -"Fleet territories: named polygons that bound which vehicle may\nserve which stop, referenced by `vehicles[].territory_ids`. These\nare request data — caller-drawn rounds, validated per call and\nnever stored. Nothing to do with clean-air zones or with the\noffline map packages of the same word."New value: +"Fleet territories: named polygons that bound which vehicle may\nserve which stop, referenced by `vehicles[].territory_ids`. These\nare request data, caller-drawn rounds, validated per call and\nnever stored. Nothing to do with clean-air zones or with the\noffline map packages of the same word."
    • changedOutput schema / properties / reloads / description
      Previous value: -"The multi-trip split: each vehicle's trips, their windows, the\ndepot each returns to, and the stated approximation. Present only\nwhen a vehicle declared `reloads`.\n\nRead the `basis` inside it before quoting arrival times. The trip\nwindows are fixed BEFORE the solve, so a lorry that tips early\ncannot lend the spare time to its next trip: stops can come back\nunassigned that a truly sequential model would have served. The\nplan is feasible, never optimistic — it cannot put a vehicle in two\nplaces at once — but it is not optimal. Re-plan after each tip\nthrough `replan_routes` for the tighter answer."New value: +"The multi-trip split: each vehicle's trips, their windows, the\ndepot each returns to, and the stated approximation. Present only\nwhen a vehicle declared `reloads`.\n\nRead the `basis` inside it before quoting arrival times. The trip\nwindows are fixed BEFORE the solve, so a lorry that tips early\ncannot lend the spare time to its next trip: stops can come back\nunassigned that a truly sequential model would have served. The\nplan is feasible, never optimistic, it cannot put a vehicle in two\nplaces at once, but it is not optimal. Re-plan after each tip\nthrough `replan_routes` for the tighter answer."
  2. Changed2 schema fields changed
    • addedOutput schema / properties / view_url
      Added value: +{
      +  "description": "A mapmap.ai link that draws this fleet plan, one route per vehicle, 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. Changed10 schema fields changed
    • addedInput 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"
      +  }
      +]
    • changedInput 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."
    • removedInput 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"
      -  }
      -}
    • removedInput schema / $defs / LatLon / required
      Removed value: -[
      -  "lat",
      -  "lon"
      -]
    • removedInput schema / $defs / LatLon / type
      Removed value: -"object"
    • 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"
  4. Changed16 schema fields changed
    • 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 / OptimiseVehicleSpec / properties / reloads
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/ReloadsSpec"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "Let this vehicle return to a depot, reload and go out again — the\nwaste-collection tipping round, the van that comes back for a\nsecond wave of parcels."
      +}
    • addedInput schema / $defs / OptimiseVehicleSpec / properties / territory_ids
      Added value: +{
      +  "description": "Ids of the request's `territories` this vehicle may work in.\nOmitted or empty, the vehicle is UNRESTRICTED and may serve any\ntask, inside a territory or outside every one of them. Listed, the\nvehicle may serve a task only if that task sits inside at least one\nof the named territories.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": [
      +    "array",
      +    "null"
      +  ]
      +}
    • addedInput schema / $defs / RelaxSpec
      Added value: +{
      +  "description": "What the caller is willing to give up if the first solve leaves work\nunassigned. At least one field is required.",
      +  "properties": {
      +    "allow_overtime_s": {
      +      "description": "Extend every vehicle's shift END by this many seconds. Shift starts\nare never moved earlier — a driver cannot begin before they begin.",
      +      "format": "int64",
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    },
      +    "time_windows_by_s": {
      +      "description": "Widen every task time window by this many seconds at EACH end. A\n09:00–12:00 window with 1800 becomes 08:30–12:30.",
      +      "format": "int64",
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    }
      +  },
      +  "type": "object"
      +}
    • addedInput schema / $defs / ReloadsSpec
      Added value: +{
      +  "description": "A vehicle's multi-trip reload plan.",
      +  "properties": {
      +    "depot": {
      +      "anyOf": [
      +        {
      +          "$ref": "#/$defs/LatLon"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ],
      +      "description": "Where the vehicle reloads. Omitted, its own `start` is used (or its\n`end` if it declared only that)."
      +    },
      +    "max_trips": {
      +      "description": "How many trips this vehicle may run in its shift, 2–5. A BUDGET,\nnot a prediction: the shift is cut into that many fixed windows\nbefore the solve, so asking for five trips on a shift that supports\nthree shrinks every window to a fifth and can make the whole day\nworse. Ask for the number of trips you actually expect to run.",
      +      "format": "uint32",
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "reload_time_s": {
      +      "description": "Seconds at the depot between trips — tipping, reloading, the\nweighbridge. Held out of the shift before it is partitioned, so it\nis never accidentally spent driving.",
      +      "format": "uint32",
      +      "minimum": 0,
      +      "type": [
      +        "integer",
      +        "null"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "max_trips"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / $defs / TerritorySpec
      Added value: +{
      +  "description": "One named territory: a polygon that bounds which vehicle may serve\nwhich stop.",
      +  "properties": {
      +    "id": {
      +      "description": "Caller-chosen id, echoed back and referenced by\n`vehicles[].territory_ids`. Must be unique within the request.",
      +      "type": "string"
      +    },
      +    "polygon": {
      +      "description": "The outer ring as GeoJSON `[lon, lat]` positions — longitude\nFIRST. Closed or open; an unclosed ring is closed for you.",
      +      "items": {
      +        "items": {
      +          "format": "double",
      +          "type": "number"
      +        },
      +        "maxItems": 2,
      +        "minItems": 2,
      +        "type": "array"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "id",
      +    "polygon"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / avoid_zones
      Added value: +{
      +  "description": "Keep the optimisation's travel-time matrix out of every zone the\ndeclared vehicle would be charged or banned in. Requires\n`emissions`.",
      +  "type": [
      +    "boolean",
      +    "null"
      +  ]
      +}
    • addedInput schema / properties / emissions
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/EmissionsSpec"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "The fleet's emission declaration, for UK clean-air / low-emission\nzone assessment. On its own it annotates: the response's `zones`\nblock names every zone containing one of the problem's own\nlocations and what this vehicle would pay there. With\n`avoid_zones` it also steers the internal travel-time matrix away\nfrom those zones, so the plan itself changes."
      +}
    • addedInput schema / properties / relax_if_unassigned
      Added value: +{
      +  "anyOf": [
      +    {
      +      "$ref": "#/$defs/RelaxSpec"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "Re-solve ONCE with these relaxations if the first solve leaves work\nunassigned, and say honestly which plan came back. At most one\nsecond solve, never beyond the caps you state, and the relaxed plan\nis returned only if it assigns MORE work than the first — giving\naway constraints for nothing is strictly worse than not giving them\naway. Breaks are never widened, nor are capacities, skills,\nterritories or task caps: only time windows move, and only by the\nstated amounts. Bills as two solves when the second one runs."
      +}
    • addedInput schema / properties / territories
      Added value: +{
      +  "description": "Fleet territories: named polygons that bound which vehicle may\nserve which stop, referenced by `vehicles[].territory_ids`. These\nare request data — caller-drawn rounds, validated per call and\nnever stored. Nothing to do with clean-air zones or with the\noffline map packages of the same word.",
      +  "items": {
      +    "$ref": "#/$defs/TerritorySpec"
      +  },
      +  "type": [
      +    "array",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / relaxation
      Added value: +{
      +  "description": "The relaxation report: the caps requested, whether a second solve\nran, whether ITS plan is the one returned, what was widened, and\nwhat is still unassigned. Present only when `relax_if_unassigned`\nwas declared.\n\nAlways read `second_solve` and `relaxed_plan_used` before telling\nanyone the day fits. A plan produced under relaxation has had\npromises moved, and the block is what says so."
      +}
    • addedOutput schema / properties / reloads
      Added value: +{
      +  "description": "The multi-trip split: each vehicle's trips, their windows, the\ndepot each returns to, and the stated approximation. Present only\nwhen a vehicle declared `reloads`.\n\nRead the `basis` inside it before quoting arrival times. The trip\nwindows are fixed BEFORE the solve, so a lorry that tips early\ncannot lend the spare time to its next trip: stops can come back\nunassigned that a truly sequential model would have served. The\nplan is feasible, never optimistic — it cannot put a vehicle in two\nplaces at once — but it is not optimal. Re-plan after each tip\nthrough `replan_routes` for the tighter answer."
      +}
    • addedOutput schema / properties / territories
      Added value: +{
      +  "description": "How the territories bound the plan: which vehicle was eligible for\nwhat, and any task no eligible vehicle existed for. Present only\nwhen `territories` was declared."
      +}
    • addedOutput schema / properties / zones
      Added value: +{
      +  "description": "Clean-air / low-emission zones touching the problem's own\nlocations, and what the declared vehicle pays in each. Present only\nwhen `emissions` was declared."
      +}
  5. First observed

TDQS

A4.5/5.0
Behavior4/5

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

No annotations are supplied, so the description carries the full burden and does so unusually well: it discloses billing ('bills as two solves when the second one runs'), the fact that the tool refuses rather than silently ignoring gateway features, that the reload split is fixed before the solve and therefore conservative, that max_trips is a budget not a prediction, and that relaxation is capped at one extra solve and only returned if it assigns more work. Auth/permission requirements and any rate limits beyond 'fair use' are not stated, which keeps it short of a 5.

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

Conciseness3/5

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

The critical facts are front-loaded (what it is, then inputs, then limits), but the body is a dense wall of text with conversational asides ('cargo-bike and courier fleets welcome', 'the tipping round', 'it cannot put a lorry in two places at once') that cost scanning time. Much of the reloads/relaxation material is also duplicated in the schema field descriptions, so the length is not fully earned.

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 9-parameter VRP tool with nested specs, an output schema, and no annotations, the description covers every capability surface an agent needs: input shapes, the truck/ADR legality consequence, territories, reloads, relaxation, emissions zones, the gateway precondition, billing, and the returned view_url. Nothing material to a correct invocation 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 description coverage is 100%, so the baseline is 3; the description climbs above it by explaining cross-parameter semantics the schema cannot state per-field — how territory_ids interacts with territories (unrestricted when empty), how emissions+avoid_zones changes the matrix rather than merely annotating, and how relax_if_unassigned interacts with the first solve. This is interpretive value on top of documented fields.

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: 'Optimise multi-vehicle, multi-stop delivery plans (VRP)', then enumerates the input shapes (vehicles/jobs/shipments). It explicitly distinguishes itself from three siblings by name — cluster for splitting oversized problems, submit_optimise_job for the async lane, and replan_routes for post-tip tightening — so an agent can route to the right tool without opening a schema.

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

Usage Guidelines5/5

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

Gives concrete when-to-use and when-not guidance: the 200-location / matrix-span fair-use ceiling and the fallback ('cluster the stops … or submit the whole problem to the asynchronous lane'), plus the requirement to re-plan with replan_routes after each reload. It also states the precondition that territories/reloads/relaxation/zones need a configured MapMap gateway.

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