diff --git a/docs.json b/docs.json index 9f9a182..2ae180f 100644 --- a/docs.json +++ b/docs.json @@ -40,7 +40,11 @@ { "group": "MCP", "pages": [ - "mcp/overview" + "mcp/overview", + "mcp/geocode", + "mcp/route", + "mcp/table", + "mcp/optimize" ] }, { diff --git a/mcp/geocode.mdx b/mcp/geocode.mdx new file mode 100644 index 0000000..4d698b1 --- /dev/null +++ b/mcp/geocode.mdx @@ -0,0 +1,115 @@ +--- +title: "Geocode Tool" +description: "Convert a place name or address into coordinates — structured fields, filters, and best-match results." +icon: "search" +--- + +## Overview + +Search for a place or address and convert it into coordinates. + +Use this tool when the user provides: + +* a place name +* a landmark +* a business +* a street address +* another location description + +Do not use it when the user already provides coordinates in `longitude,latitude` format. + +## Structured input + +The search is structured. Parse the user's location into the fields that can be determined: + +* `name` — place, landmark, or business name +* `housenumber` — house or building number +* `street` — street name +* `postcode` — postal or ZIP code +* `city` — city or locality +* `country` — country + +Only provide fields that are known from the user's request. + +Do not invent or guess missing address components. + +For example: + +```json +{ + "name": "Marina Bay Sands", + "housenumber": "10", + "street": "Bayfront Avenue", + "postcode": "018956", + "city": "Singapore", + "country": "Singapore" +} +``` + +When the user's context provides a country or city, include it to disambiguate common, abbreviated, or misspelled place names. + +## Limit and filters + +`limit` is optional and defaults to `1`. + +The maximum value is `10`. + +Use a larger `limit` when the location is ambiguous or the user asks for alternatives. + +`filters` can optionally restrict the search. + +For example: + +```json +{ + "name": "Marina Bay Sands", + "country": "Singapore", + "limit": 5, + "filters": ["countrycode:sg"] +} +``` + +## Output + +```json +{ + "results": [ + { + "longitude": 103.859, + "latitude": 1.2834, + "coordinates": "103.859,1.2834", + "formatted": "Marina Bay Sands, 10 Bayfront Avenue, 018956, Singapore", + "place_id": "51667b3e...", + "country_code": "sg", + "result_type": "building" + } + ] +} +``` + +Results are ordered by relevance. + +By default, the best matching result is returned. + +If multiple results are requested, choose the result that best matches the user's intended location. + +The `coordinates` value is in `longitude,latitude` format and can be passed directly to [`route`](/mcp/route), [`table`](/mcp/table), or [`optimize`](/mcp/optimize). + +When using geocode as part of a routing workflow, verify that the selected result matches the user's intended place before passing its coordinates to the next tool. + +If no result matches, the tool returns an error so the assistant can refine the search. + +## Example + +Prompt for an MCP-capable agent, e.g. Claude or Codex + +```shell +What are the latitude and longitude for 75 Jln Kelabu Asap, Singapore 278268? + +# The coordinates for 75 Jalan Kelabu Asap, Singapore 278268 are: +# +# - Latitude: 1.310368 +# - Longitude: 103.797116 +# +# (In longitude,latitude format: 103.797116,1.310368) +``` diff --git a/mcp/optimize.mdx b/mcp/optimize.mdx new file mode 100644 index 0000000..fdefab1 --- /dev/null +++ b/mcp/optimize.mdx @@ -0,0 +1,215 @@ +--- +title: "Optimize Tool" +description: "Assign jobs to vehicles and determine the order in which each vehicle visits its stops." +icon: "truck" +--- + +## Overview + +Assign jobs to vehicles and determine the order in which each vehicle should visit its assigned jobs. + +Use this tool when the user needs to: + +* assign multiple deliveries or pickups to vehicles +* plan routes for a fleet +* determine the order of multiple stops +* optimize a multi-vehicle routing solution + +Do not use it for a single route. Use [`route`](/mcp/route). + +Do not use it only to compare distances or travel times between locations. Use [`table`](/mcp/table). + +## Input + +```json +{ + "vehicles": [ + { + "id": 1, + "start": "103.7923,1.3246", + "end": "103.7923,1.3246" + }, + { + "id": 2, + "start": "103.8232,1.3241", + "end": "103.8232,1.3241" + } + ], + "jobs": [ + { + "id": 1, + "location": "103.7975,1.3104" + }, + { + "id": 2, + "location": "103.7843,1.3149" + }, + { + "id": 3, + "location": "103.7976,1.3198" + } + ] +} +``` + +Every vehicle must have a unique `id`. + +Every job must have a unique `id` and a `location`. + +Locations must use: + +```text +longitude,latitude +``` + +Each vehicle must have at least a `start` or an `end`. + +For a round trip, set both `start` and `end` to the same location: + +```json +{ + "id": 1, + "start": "103.7923,1.3246", + "end": "103.7923,1.3246" +} +``` + +If `start` or `end` is omitted, the vehicle may start or end anywhere. + +## Vehicle profiles + +Each vehicle can use its own routing profile. + +Use: + +```json +"profile": "motorcycle" +``` + +when the user explicitly asks for a motorcycle or motorbike route. + +Otherwise, omit `profile` to use the default driving profile. + +For example: + +```json +{ + "id": 1, + "profile": "motorcycle", + "start": "103.7923,1.3246", + "end": "103.7923,1.3246" +} +``` + +## Output + +A simplified result looks like: + +```json +{ + "summary": { + "cost": 2733, + "routes": 2, + "unassigned": 0, + "duration": 2733 + }, + "routes": [ + { + "vehicle": 1, + "cost": 1144, + "duration": 1144, + "steps": [ + { + "type": "start", + "location": [103.7923, 1.3246], + "arrival": 0 + }, + { + "type": "job", + "job": 2, + "location": [103.7843, 1.3149], + "arrival": 269, + "duration": 269 + }, + { + "type": "job", + "job": 1, + "location": [103.7975, 1.3104], + "arrival": 673, + "duration": 673 + }, + { + "type": "end", + "location": [103.7923, 1.3246], + "arrival": 1144, + "duration": 1144 + } + ] + } + ], + "unassigned": [] +} +``` + +Use `routes[].steps` to determine: + +* which vehicle serves each job +* the order in which jobs are visited +* when each job is reached + +A `job` step contains the job ID, arrival time, travel duration, and travel distance for reaching that job. + +Always check `unassigned`. + +**Do not assume that every job will be assigned.** + +If the user provides place names or addresses instead of coordinates, call [`geocode`](/mcp/geocode) first for every location and use the selected coordinates in the optimization request. + +## Example + +Prompt for an MCP-capable agent, e.g. Claude or Codex + +```shell +I have two vans available to pick up packages from six customers. + +Vans: +- V1 starts at 249 Sixth Ave, Singapore 275771 +- V2 starts at 8 Harlyn Rd, Singapore 299445 + +Customers: +- C1: 75 Jln Kelabu Asap, Singapore 278268 +- C2: 20 Mount Sinai Rd, Singapore 276854 +- C3: 10 Bin Tong Park, Singapore 269792 +- C4: 9 Cluny Park, Singapore 259619 +- C5: 28 Nassim Rd, Singapore 258403 +- C6: 30 Chancery Ln, Singapore 309549 + +How should these six pickup tasks be assigned and ordered between the two vans? + +# Solved — all 6 jobs assigned, none left unassigned. Optimal assignment: +# +# Van V1 — starts at 249 Sixth Ave (total ~19.4 min) +# ┌──────┬──────────┬────────────────────┬────────────┐ +# │ Stop │ Customer │ Address │ Arrives at │ +# ├──────┼──────────┼────────────────────┼────────────┤ +# │ 1 │ C2 │ 20 Mount Sinai Rd │ ~6 min │ +# ├──────┼──────────┼────────────────────┼────────────┤ +# │ 2 │ C1 │ 75 Jln Kelabu Asap │ ~13 min │ +# ├──────┼──────────┼────────────────────┼────────────┤ +# │ 3 │ C3 │ 10 Bin Tong Park │ ~17 min │ +# └──────┴──────────┴────────────────────┴────────────┘ +# +# Van V2 — starts at 8 Harlyn Rd (total ~29.0 min) +# ┌──────┬──────────┬────────────────┬────────────┐ +# │ Stop │ Customer │ Address │ Arrives at │ +# ├──────┼──────────┼────────────────┼────────────┤ +# │ 1 │ C6 │ 30 Chancery Ln │ ~5 min │ +# ├──────┼──────────┼────────────────┼────────────┤ +# │ 2 │ C5 │ 28 Nassim Rd │ ~14 min │ +# ├──────┼──────────┼────────────────┼────────────┤ +# │ 3 │ C4 │ 9 Cluny Park │ ~23 min │ +# └──────┴──────────┴────────────────┴────────────┘ +# +# Each van returns to its own depot afterward. The solver minimizes total fleet driving time (~48.5 min combined), +# which is why V1 picks up the western cluster and V2 covers the eastern side +``` diff --git a/mcp/overview.mdx b/mcp/overview.mdx index 7b6dc31..127335a 100644 --- a/mcp/overview.mdx +++ b/mcp/overview.mdx @@ -12,12 +12,12 @@ Designed for Southeast Asia. ## What you can do -| Tool | What it does | -| ---------- | ------------------------------------------------------------ | -| `geocode` | Place or address → coordinates | -| `route` | Calculate one route | -| `table` | Compare travel times or distances between multiple locations | -| `optimize` | Assign jobs to vehicles and order their stops | +| Tool | What it does | +| --------- | ------------------------------------------------------------ | +| [`geocode`](/mcp/geocode) | Place or address → coordinates | +| [`route`](/mcp/route) | Calculate one route | +| [`table`](/mcp/table) | Compare travel times or distances between multiple locations | +| [`optimize`](/mcp/optimize) | Assign jobs to vehicles and order their stops | The tools are designed around three simple tasks: @@ -91,577 +91,20 @@ A simple rule: ## Tools -### `route` - -Calculate a route between two locations. - -Use this tool when the user needs to: - -* calculate driving distance -* estimate travel time -* get a route between two locations -* get route geometry -* understand which roads a route uses -* avoid specific road types - -Do not use it for comparing many origin-destination pairs. Use `table` instead. - -Do not use it for assigning jobs to vehicles or ordering multiple stops. Use `optimize` instead. - -#### Input - -```json -{ - "origin": "103.8198,1.3521", - "destination": "103.9915,1.3644" -} -``` - -Coordinates must use: - -```text -longitude,latitude -``` - -For example: - -```text -103.8198,1.3521 -``` - -#### Motorcycle routing - -`profile` is optional. - -Set it to `"motorcycle"` when the user explicitly asks for a motorcycle or motorbike route. - -Otherwise, omit `profile` to use the default driving profile. - -```json -{ - "origin": "103.8198,1.3521", - "destination": "103.9915,1.3644", - "profile": "motorcycle" -} -``` - -#### Avoiding roads - -Use `exclude` when the user explicitly asks to avoid a road type. - -Supported values: - -* `toll` -* `motorway` -* `ferry` - -For example: - -```json -{ - "origin": "103.8198,1.3521", - "destination": "103.9915,1.3644", - "exclude": ["toll"] -} -``` - -Road avoidance is a preference, not a guarantee. The engine avoids the specified road type when a reasonable alternative exists. - -#### Output - -```json -{ - "distance_meters": 18500, - "duration_seconds": 1500, - "profile": "driving", - "origin": { - "input": "103.8198,1.3521", - "snapped": [103.8197, 1.3520], - "name": "Example Road", - "distance": 4.2 - }, - "destination": { - "input": "103.9915,1.3644", - "snapped": [103.9915, 1.3644], - "name": "Airport Boulevard", - "distance": 8.1 - }, - "geometry": "ka|`@_ceeEnAqB...", - "summary": { - "roads": ["East Coast Parkway"], - "tolls": false, - "ferry": false - } -} -``` - -* `distance_meters` — route distance in meters -* `duration_seconds` — estimated travel time in seconds -* `profile` — routing profile used -* `geometry` — simplified encoded polyline for the route -* `summary.roads` — main roads used by the route -* `summary.tolls` — whether the route uses toll roads -* `summary.ferry` — whether the route includes a ferry crossing - -If the user provides place names or addresses instead of coordinates, call `geocode` first. - ---- - -### `table` - -Calculate a distance and/or travel-time matrix between multiple locations. - -Use this tool when the user needs to: - -* find the nearest driver, vehicle, store, or facility -* compare several destinations -* compare multiple origin-destination pairs -* build a distance or travel-time matrix - -Do not use it for a single route between two locations. Use `route` instead. - -#### Input - -```json -{ - "coordinates": [ - "103.8391,1.2771", - "103.8590,1.2834", - "103.7986,1.2885" - ] -} -``` - -Each coordinate has a stable zero-based index based on its position in the `coordinates` array. - -For example: - -```text -coordinates[0] → index 0 -coordinates[1] → index 1 -coordinates[2] → index 2 -``` - -Matrix rows correspond to **sources**. - -Matrix columns correspond to **destinations**. - -A matrix value at `[row][column]` represents the route from that source to that destination. - -For example: - -```text -durations[0][2] -``` - -means the travel time from coordinate `0` to coordinate `2`. - -The response includes `sources` and `destinations` with the original coordinate indices so the matrix can be mapped back to the user's locations. - -#### Sources and destinations - -Optional `sources` and `destinations` restrict the matrix to subsets of the coordinate indices. - -For example: - -```json -{ - "coordinates": [ - "103.8391,1.2771", - "103.8590,1.2834", - "103.7986,1.2885" - ], - "sources": [0], - "destinations": [1, 2] -} -``` - -This calculates routes from coordinate `0` to coordinates `1` and `2`. - -#### Annotations - -Use: - -```json -"annotations": ["duration"] -``` - -for travel times. - -Use: - -```json -"annotations": ["distance"] -``` - -for distances. - -Use: - -```json -"annotations": ["duration", "distance"] -``` - -for both. - -If omitted, both are returned. - -* `duration` — travel time in seconds -* `distance` — distance in meters - -#### Motorcycle routing - -Set: - -```json -"profile": "motorcycle" -``` - -when the user explicitly asks for motorcycle or motorbike routing. - -Otherwise, omit `profile`. - -#### Nearest-driver example - -For a question such as: - -> Which driver is closest to the customer? - -Keep the locations in a fixed order: - -```text -coordinates[0] = customer -coordinates[1] = driver A -coordinates[2] = driver B -coordinates[3] = driver C -``` - -Then: - -1. Use `[0]` as the source. -2. Use the driver indices as destinations. -3. Read the corresponding values from the first matrix row. -4. Ignore `null` values. -5. Choose the smallest distance or duration, depending on the user's request. - -For example: - -```json -{ - "coordinates": [ - "103.8391,1.2771", - "103.8590,1.2834", - "103.7986,1.2885" - ], - "sources": [0], - "destinations": [1, 2], - "annotations": ["distance"] -} -``` - -#### Output - -```json -{ - "code": "Ok", - "durations": [ - [0, 1860, null], - [1850, 0, 2100], - [null, 2110, 0] - ], - "distances": [ - [0, 14200, null], - [14100, 0, 18400], - [null, 18200, 0] - ], - "sources": [ - { - "index": 0, - "name": "Duxton Road", - "location": [103.8391, 1.2771], - "distance": 12.3 - } - ], - "destinations": [ - { - "index": 1, - "name": "Bayfront Avenue", - "location": [103.8590, 1.2834], - "distance": 8.4 - } - ] -} -``` - -`durations` are in seconds. - -`distances` are in meters. - -A matrix value of `null` means that the origin-destination pair is unreachable. - -**Never interpret `null` as zero.** - -If the user provides place names or addresses instead of coordinates, call `geocode` first for every place. Keep the locations in the same order when constructing the matrix request. - ---- - -### `geocode` - -Search for a place or address and convert it into coordinates. - -Use this tool when the user provides: - -* a place name -* a landmark -* a business -* a street address -* another location description - -Do not use it when the user already provides coordinates in `longitude,latitude` format. - -#### Structured input - -The search is structured. Parse the user's location into the fields that can be determined: - -* `name` — place, landmark, or business name -* `housenumber` — house or building number -* `street` — street name -* `postcode` — postal or ZIP code -* `city` — city or locality -* `country` — country - -Only provide fields that are known from the user's request. - -Do not invent or guess missing address components. - -For example: - -```json -{ - "name": "Marina Bay Sands", - "housenumber": "10", - "street": "Bayfront Avenue", - "postcode": "018956", - "city": "Singapore", - "country": "Singapore" -} -``` - -When the user's context provides a country or city, include it to disambiguate common, abbreviated, or misspelled place names. - -#### Limit and filters - -`limit` is optional and defaults to `1`. - -The maximum value is `10`. - -Use a larger `limit` when the location is ambiguous or the user asks for alternatives. - -`filters` can optionally restrict the search. - -For example: - -```json -{ - "name": "Marina Bay Sands", - "country": "Singapore", - "limit": 5, - "filters": ["countrycode:sg"] -} -``` - -#### Output - -```json -{ - "results": [ - { - "longitude": 103.859, - "latitude": 1.2834, - "coordinates": "103.859,1.2834", - "formatted": "Marina Bay Sands, 10 Bayfront Avenue, 018956, Singapore", - "place_id": "51667b3e...", - "country_code": "sg", - "result_type": "building" - } - ] -} -``` - -Results are ordered by relevance. - -By default, the best matching result is returned. - -If multiple results are requested, choose the result that best matches the user's intended location. - -The `coordinates` value is in `longitude,latitude` format and can be passed directly to `route`, `table`, or `optimize`. - -When using geocode as part of a routing workflow, verify that the selected result matches the user's intended place before passing its coordinates to the next tool. - -If no result matches, the tool returns an error so the assistant can refine the search. - ---- - -### `optimize` - -Assign jobs to vehicles and determine the order in which each vehicle should visit its assigned jobs. - -Use this tool when the user needs to: - -* assign multiple deliveries or pickups to vehicles -* plan routes for a fleet -* determine the order of multiple stops -* optimize a multi-vehicle routing solution - -Do not use it for a single route. Use `route`. - -Do not use it only to compare distances or travel times between locations. Use `table`. - -#### Input - -```json -{ - "vehicles": [ - { - "id": 1, - "start": "103.7923,1.3246", - "end": "103.7923,1.3246" - }, - { - "id": 2, - "start": "103.8232,1.3241", - "end": "103.8232,1.3241" - } - ], - "jobs": [ - { - "id": 1, - "location": "103.7975,1.3104" - }, - { - "id": 2, - "location": "103.7843,1.3149" - }, - { - "id": 3, - "location": "103.7976,1.3198" - } - ] -} -``` - -Every vehicle must have a unique `id`. - -Every job must have a unique `id` and a `location`. - -Locations must use: - -```text -longitude,latitude -``` - -Each vehicle must have at least a `start` or an `end`. - -For a round trip, set both `start` and `end` to the same location: - -```json -{ - "id": 1, - "start": "103.7923,1.3246", - "end": "103.7923,1.3246" -} -``` - -If `start` or `end` is omitted, the vehicle may start or end anywhere. - -#### Vehicle profiles - -Each vehicle can use its own routing profile. - -Use: - -```json -"profile": "motorcycle" -``` - -when the user explicitly asks for a motorcycle or motorbike route. - -Otherwise, omit `profile` to use the default driving profile. - -For example: - -```json -{ - "id": 1, - "profile": "motorcycle", - "start": "103.7923,1.3246", - "end": "103.7923,1.3246" -} -``` - -#### Output - -A simplified result looks like: - -```json -{ - "summary": { - "cost": 2733, - "routes": 2, - "unassigned": 0, - "duration": 2733 - }, - "routes": [ - { - "vehicle": 1, - "cost": 1144, - "duration": 1144, - "steps": [ - { - "type": "start", - "location": [103.7923, 1.3246], - "arrival": 0 - }, - { - "type": "job", - "job": 2, - "location": [103.7843, 1.3149], - "arrival": 269, - "duration": 269 - }, - { - "type": "job", - "job": 1, - "location": [103.7975, 1.3104], - "arrival": 673, - "duration": 673 - }, - { - "type": "end", - "location": [103.7923, 1.3246], - "arrival": 1144, - "duration": 1144 - } - ] - } - ], - "unassigned": [] -} -``` - -Use `routes[].steps` to determine: - -* which vehicle serves each job -* the order in which jobs are visited -* when each job is reached - -A `job` step contains the job ID, arrival time, travel duration, and travel distance for reaching that job. - -Always check `unassigned`. - -**Do not assume that every job will be assigned.** - -If the user provides place names or addresses instead of coordinates, call `geocode` first for every location and use the selected coordinates in the optimization request. + + + Convert a place name or address into coordinates. + + + Calculate one route between two locations. + + + Compare travel times or distances between multiple locations. + + + Assign jobs to vehicles and order their stops. + + --- diff --git a/mcp/route.mdx b/mcp/route.mdx new file mode 100644 index 0000000..ed6229f --- /dev/null +++ b/mcp/route.mdx @@ -0,0 +1,138 @@ +--- +title: "Route Tool" +description: "Calculate one driving route between two locations — distance, duration, geometry, and road information." +icon: "route" +--- + +## Overview + +Calculate a route between two locations. + +Use this tool when the user needs to: + +* calculate driving distance +* estimate travel time +* get a route between two locations +* get route geometry +* understand which roads a route uses +* avoid specific road types + +Do not use it for comparing many origin-destination pairs. Use [`table`](/mcp/table) instead. + +Do not use it for assigning jobs to vehicles or ordering multiple stops. Use [`optimize`](/mcp/optimize) instead. + +## Input + +```json +{ + "origin": "103.8198,1.3521", + "destination": "103.9915,1.3644" +} +``` + +Coordinates must use: + +```text +longitude,latitude +``` + +For example: + +```text +103.8198,1.3521 +``` + +## Motorcycle routing + +`profile` is optional. + +Set it to `"motorcycle"` when the user explicitly asks for a motorcycle or motorbike route. + +Otherwise, omit `profile` to use the default driving profile. + +```json +{ + "origin": "103.8198,1.3521", + "destination": "103.9915,1.3644", + "profile": "motorcycle" +} +``` + +## Avoiding roads + +Use `exclude` when the user explicitly asks to avoid a road type. + +Supported values: + +* `toll` +* `motorway` +* `ferry` + +For example: + +```json +{ + "origin": "103.8198,1.3521", + "destination": "103.9915,1.3644", + "exclude": ["toll"] +} +``` + +Road avoidance is a preference, not a guarantee. The engine avoids the specified road type when a reasonable alternative exists. + +## Output + +```json +{ + "distance_meters": 18500, + "duration_seconds": 1500, + "profile": "driving", + "origin": { + "input": "103.8198,1.3521", + "snapped": [103.8197, 1.3520], + "name": "Example Road", + "distance": 4.2 + }, + "destination": { + "input": "103.9915,1.3644", + "snapped": [103.9915, 1.3644], + "name": "Airport Boulevard", + "distance": 8.1 + }, + "geometry": "ka|`@_ceeEnAqB...", + "summary": { + "roads": ["East Coast Parkway"], + "tolls": false, + "ferry": false + } +} +``` + +* `distance_meters` — route distance in meters +* `duration_seconds` — estimated travel time in seconds +* `profile` — routing profile used +* `geometry` — simplified encoded polyline for the route +* `summary.roads` — main roads used by the route +* `summary.tolls` — whether the route uses toll roads +* `summary.ferry` — whether the route includes a ferry crossing + +If the user provides place names or addresses instead of coordinates, call [`geocode`](/mcp/geocode) first. + +## Example + +Prompt for an MCP-capable agent, e.g. Claude or Codex + +```shell +How long does it take to drive from Marina Bay Sands Singapore to Changi Airport? +# - Time: ~24 minutes +# - Distance: ~19.1 km +# - Route: via East Coast Parkway (ECP) and Airport Boulevard +# - Tolls: yes — Electronic Road Pricing (ERP) may apply depending on time of day +# Traffic conditions can add time during peak hours. + +What if I'm riding a motorcycle? +# On a motorcycle, same route (via East Coast Parkway): +# - Time: ~27 minutes (26 min 31 s) +# - Distance: ~19.1 km +# - Tolls: yes, ERP applies +``` diff --git a/mcp/table.mdx b/mcp/table.mdx new file mode 100644 index 0000000..b408175 --- /dev/null +++ b/mcp/table.mdx @@ -0,0 +1,235 @@ +--- +title: "Table Tool" +description: "Compare travel times or distances between multiple locations with a distance and travel-time matrix." +icon: "table" +--- + +## Overview + +Calculate a distance and/or travel-time matrix between multiple locations. + +Use this tool when the user needs to: + +* find the nearest driver, vehicle, store, or facility +* compare several destinations +* compare multiple origin-destination pairs +* build a distance or travel-time matrix + +Do not use it for a single route between two locations. Use [`route`](/mcp/route) instead. + +## Input + +```json +{ + "coordinates": [ + "103.8391,1.2771", + "103.8590,1.2834", + "103.7986,1.2885" + ] +} +``` + +Each coordinate has a stable zero-based index based on its position in the `coordinates` array. + +For example: + +```text +coordinates[0] → index 0 +coordinates[1] → index 1 +coordinates[2] → index 2 +``` + +Matrix rows correspond to **sources**. + +Matrix columns correspond to **destinations**. + +A matrix value at `[row][column]` represents the route from that source to that destination. + +For example: + +```text +durations[0][2] +``` + +means the travel time from coordinate `0` to coordinate `2`. + +The response includes `sources` and `destinations` with the original coordinate indices so the matrix can be mapped back to the user's locations. + +## Sources and destinations + +Optional `sources` and `destinations` restrict the matrix to subsets of the coordinate indices. + +For example: + +```json +{ + "coordinates": [ + "103.8391,1.2771", + "103.8590,1.2834", + "103.7986,1.2885" + ], + "sources": [0], + "destinations": [1, 2] +} +``` + +This calculates routes from coordinate `0` to coordinates `1` and `2`. + +## Annotations + +Use: + +```json +"annotations": ["duration"] +``` + +for travel times. + +Use: + +```json +"annotations": ["distance"] +``` + +for distances. + +Use: + +```json +"annotations": ["duration", "distance"] +``` + +for both. + +If omitted, both are returned. + +* `duration` — travel time in seconds +* `distance` — distance in meters + +## Motorcycle routing + +Set: + +```json +"profile": "motorcycle" +``` + +when the user explicitly asks for motorcycle or motorbike routing. + +Otherwise, omit `profile`. + +## Nearest-driver example + +For a question such as: + +> Which driver is closest to the customer? + +Keep the locations in a fixed order: + +```text +coordinates[0] = customer +coordinates[1] = driver A +coordinates[2] = driver B +coordinates[3] = driver C +``` + +Then: + +1. Use `[0]` as the source. +2. Use the driver indices as destinations. +3. Read the corresponding values from the first matrix row. +4. Ignore `null` values. +5. Choose the smallest distance or duration, depending on the user's request. + +For example: + +```json +{ + "coordinates": [ + "103.8391,1.2771", + "103.8590,1.2834", + "103.7986,1.2885" + ], + "sources": [0], + "destinations": [1, 2], + "annotations": ["distance"] +} +``` + +## Output + +```json +{ + "code": "Ok", + "durations": [ + [0, 1860, null], + [1850, 0, 2100], + [null, 2110, 0] + ], + "distances": [ + [0, 14200, null], + [14100, 0, 18400], + [null, 18200, 0] + ], + "sources": [ + { + "index": 0, + "name": "Duxton Road", + "location": [103.8391, 1.2771], + "distance": 12.3 + } + ], + "destinations": [ + { + "index": 1, + "name": "Bayfront Avenue", + "location": [103.8590, 1.2834], + "distance": 8.4 + } + ] +} +``` + +`durations` are in seconds. + +`distances` are in meters. + +A matrix value of `null` means that the origin-destination pair is unreachable. + +**Never interpret `null` as zero.** + +If the user provides place names or addresses instead of coordinates, call [`geocode`](/mcp/geocode) first for every place. Keep the locations in the same order when constructing the matrix request. + +## Example + +Prompt for an MCP-capable agent, e.g. Claude or Codex + +```shell +I need to assign a delivery to the closest available driver by driving distance. + +Customer: +- Mondrian Singapore Duxton + +Available drivers: +- D1: Marina Bay Sands +- D2: Waterford Residence +- D3: IKEA Alexandra +- D4: VivoCity + +Compare the driving distance from each driver to the customer and recommend which driver should + +# Here's the driving distance comparison from each driver to the customer (Mondrian Singapore Duxton): +# ┌────────┬─────────────────────┬──────────┬────────────┐ +# │ Driver │ Location │ Distance │ Drive time │ +# ├────────┼─────────────────────┼──────────┼────────────┤ +# │ D1 │ Marina Bay Sands │ 3.60 km │ ~8 min │ +# ├────────┼─────────────────────┼──────────┼────────────┤ +# │ D2 │ Waterford Residence │ 2.78 km │ ~6 min │ +# ├────────┼─────────────────────┼──────────┼────────────┤ +# │ D3 │ IKEA Alexandra │ 5.33 km │ ~13 min │ +# ├────────┼─────────────────────┼──────────┼────────────┤ +# │ D4 │ VivoCity │ 3.30 km │ ~7 min │ +# └────────┴─────────────────────┴──────────┴────────────┘ +# Recommendation: D2 (Waterford Residence) — the closest by both driving distance (2.78 km) and travel time (~6 minutes). +# All four drivers are reachable, so no fallback is needed. +```