Read Upper drivers and stops; create and optimize routes, assign drivers, share routes to the app.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
WRITE: assign one or more drivers (ids from upper_list_drivers) to a route, replacing the route's drivers. Every id must be an active driver on the team. If the route was already optimized it is reset to unoptimized (needs_optimization: true), so run upper_optimize_route again. POST /ext-assign-drivers.
The route.
Driver ids to assign.
The server marks this tool as destructive. Running it may delete or overwrite data on the server or in any account you connected with your headers.
WRITE: assign one or more drivers (ids from upper_list_drivers) to a route, replacing the route's drivers. Every id must be an active driver on the team. If the route was already optimized it is reset to unoptimized (needs_optimization: true), so run upper_optimize_route again. POST /ext-assign-drivers.
| Argument | Type | Description |
|---|---|---|
| route_id* | integer | The route. |
| driver_ids* | array | Driver ids to assign. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"route_id",
"driver_ids"
],
"properties": {
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The route.",
"exclusiveMinimum": 0
},
"driver_ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"maxItems": 100,
"minItems": 1,
"description": "Driver ids to assign."
}
}
}WRITE: create a new, empty route (name, date, optimization preference, units, pickup sequencing, service time). Omitted settings fall back to the account's defaults. Returns the new route_id; add stops with upper_create_stop. Calling it twice creates two routes. POST /ext-create-route.
| Argument | Type | Description |
|---|---|---|
| units | string | Distance units: miles or km. |
| route_date | string | Route start date, yyyy-mm-dd (default today). |
| route_name | string | Route name (default: New Route). |
| optimize_for | string | Optimize for time or distance. |
| service_time | integer | Per-stop service (dwell) time in seconds. |
| pickup_settings | string | When pickups are sequenced: auto, before or after the deliveries. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"units": {
"enum": [
"miles",
"km"
],
"type": "string",
"description": "Distance units: miles or km."
},
"route_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Route start date, yyyy-mm-dd (default today)."
},
"route_name": {
"type": "string",
"maxLength": 200,
"minLength": 1,
"description": "Route name (default: New Route)."
},
"optimize_for": {
"enum": [
"time",
"distance"
],
"type": "string",
"description": "Optimize for time or distance."
},
"service_time": {
"type": "integer",
"maximum": 86400,
"minimum": 0,
"description": "Per-stop service (dwell) time in seconds."
},
"pickup_settings": {
"enum": [
"auto",
"before",
"after"
],
"type": "string",
"description": "When pickups are sequenced: auto, before or after the deliveries."
}
}
}WRITE: create a stop. The address is geocoded by Upper. Pass route_id to put it on a route (the route must not be active/in progress; an optimized route is flagged for re-optimization); omit it for an unscheduled stop. Calling it twice creates two stops. POST /ext-create-stop.
| Argument | Type | Description |
|---|---|---|
| city | string | City (overrides the geocoded value). |
| note | string | Free-text note shown to the driver. |
| string | Contact email. | |
| phone | string | Contact phone number; non-digits are stripped by Upper. |
| state | string | State or region (overrides the geocoded value). |
| address* | string | Street address of the stop (geocoded by Upper). |
| zipcode | string | Postal code (overrides the geocoded value). |
| end_time | string | Latest service time (time window end), HH:MM or HH:MM:SS. |
| route_id | integer | Route to attach the stop to; omit for an unscheduled stop. |
The workspace's five capacity-field slots (capacity1 - capacity5: label, unit, enabled) used for load planning. GET /ext-get-capacity-fields.
No arguments.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {}
}The workspace's five stop custom-field slots (custom1 - custom5: type, label, enabled, required) and which are enabled. Needs the Custom fields feature in the Upper plan. GET /ext-get-custom-fields.
No arguments.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {}
}Check whether a route is optimized: status is optimized, pending (still running) or not_optimized, plus the queue_id of the last job. Poll this after upper_optimize_route. GET /ext-optimization-status.
| Argument | Type | Description |
|---|---|---|
| route_id* | integer | The route id. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"route_id"
],
"properties": {
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The route id.",
"exclusiveMinimum": 0
}
}
}List the active drivers on the Upper team that owns the API token: id, name, email and phone. Use the ids with upper_assign_drivers and upper_share_route_to_drivers. GET /ext-get-drivers.
No arguments.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {}
}List the team's stops in optimized order: address, coordinates, contact, time window, duration, status, route_id and custom ids. Pass route_id for one route (optionally scheduled=true/false); pass unscheduled=true (without route_id) for stops not on any route; with no filter all active stops are returned. Upper has no paging, so this tool pages locally: `limit` stops (default 100, max 500) starting at `offset`; the reply says if more remain (truncated, next_offset). GET /ext-get-stops.
| Argument | Type | Description |
|---|---|---|
| limit | integer | Most stops to return, 1-500 (default 100). |
| offset | integer | Skip this many stops (use next_offset from the previous reply to read on). |
| route_id | integer | Only the stops on this route. |
| scheduled | boolean | With route_id only: true = scheduled stops, false = unscheduled stops of that route. |
| unscheduled | boolean | Without route_id: true = unscheduled stops across all routes. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"limit": {
"type": "integer",
"maximum": 500,
"description": "Most stops to return, 1-500 (default 100).",
"exclusiveMinimum": 0
},
"offset": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0,
"description": "Skip this many stops (use next_offset from the previous reply to read on)."
},
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Only the stops on this route.",
"exclusiveMinimum": 0
},
"scheduled": {
"type": "boolean",
"description": "With route_id only: true = scheduled stops, false = unscheduled stops of that route."
},
"unscheduled": {
"type": "boolean",
"description": "Without route_id: true = unscheduled stops across all routes."
}
}
}WRITE: start optimizing a route's stop order. The route needs at least one stop and one assigned driver (upper_assign_drivers). It runs asynchronously: this returns status pending and a queue_id, then poll upper_get_optimization_status. If a job is already running, that job is returned. POST /ext-optimize-route.
| Argument | Type | Description |
|---|---|---|
| route_id* | integer | The route to optimize. |
| timezone | string | IANA timezone for the optimization, for example America/New_York. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"route_id"
],
"properties": {
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The route to optimize.",
"exclusiveMinimum": 0
},
"timezone": {
"type": "string",
"pattern": "^[A-Za-z0-9_+\\-/]+$",
"maxLength": 64,
"minLength": 1,
"description": "IANA timezone for the optimization, for example America/New_York."
}
}
}WRITE: push a route to the drivers' mobile app NOW, which sends each driver a notification. Without driver_ids the route's assigned drivers are used; with them, every id must be an active driver on the team. Sending twice notifies twice. Confirm with the user before calling. POST /ext-share-to-driver.
| Argument | Type | Description |
|---|---|---|
| route_id* | integer | The route to share. |
| timezone | string | IANA timezone, for example America/New_York. |
| driver_ids | array | Drivers to notify (default: the route's assigned drivers). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"route_id"
],
"properties": {
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The route to share.",
"exclusiveMinimum": 0
},
"timezone": {
"type": "string",
"pattern": "^[A-Za-z0-9_+\\-/]+$",
"maxLength": 64,
"minLength": 1,
"description": "IANA timezone, for example America/New_York."
},
"driver_ids": {
"type": "array",
"items": {
"type": "integer",
"maximum": 9007199254740991,
"exclusiveMinimum": 0
},
"maxItems": 100,
"minItems": 1,
"description": "Drivers to notify (default: the route's assigned drivers)."
}
}
}WRITE: change settings of an existing route (name, date, optimize_for, units, pickup_settings, service_time). Only the fields you pass change. POST /ext-update-route.
| Argument | Type | Description |
|---|---|---|
| units | string | Distance units: miles or km. |
| route_id* | integer | The route to update. |
| route_date | string | New start date, yyyy-mm-dd. |
| route_name | string | New route name. |
| optimize_for | string | Optimize for time or distance. |
| service_time | integer | Per-stop service (dwell) time in seconds. |
| pickup_settings | string | When pickups are sequenced: auto, before or after. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"route_id"
],
"properties": {
"units": {
"enum": [
"miles",
"km"
],
"type": "string",
"description": "Distance units: miles or km."
},
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The route to update.",
"exclusiveMinimum": 0
},
"route_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "New start date, yyyy-mm-dd."
},
"route_name": {
"type": "string",
"maxLength": 200,
"minLength": 1,
"description": "New route name."
},
"optimize_for": {
"enum": [
"time",
"distance"
],
"type": "string",
"description": "Optimize for time or distance."
},
"service_time": {
"type": "integer",
"maximum": 86400,
"minimum": 0,
"description": "Per-stop service (dwell) time in seconds."
},
"pickup_settings": {
"enum": [
"auto",
"before",
"after"
],
"type": "string",
"description": "When pickups are sequenced: auto, before or after."
}
}
}WRITE: change an existing stop; only the fields you pass change. A new address is re-geocoded (city/state/zipcode you pass with it are ignored); city/state/zipcode apply only without an address. Passing route_id moves the stop to that route. Editing a stop on an optimized route flags the route for re-optimization; stops on an active route cannot be edited. POST /ext-update-stop.
| Argument | Type | Description |
|---|---|---|
| city | string | City (only used when no address is passed). |
| note | string | Free-text note shown to the driver. |
| string | Contact email. | |
| phone | string | Contact phone number; non-digits are stripped by Upper. |
| state | string | State or region (only used when no address is passed). |
| address | string | New street address (re-geocoded). |
| stop_id* | integer | The stop to update. |
| zipcode | string | Postal code (only used when no address is passed). |
| nick_name |
| string |
| Short label for the stop. |
| pin_color | string | Map pin colour, hex like #FF6600. |
| stop_type | string | Stop type, for example Delivery or Pickup. |
| start_time | string | Earliest service time (time window start), HH:MM or HH:MM:SS. |
| company_name | string | Company name for the stop. |
| contact_name | string | Contact (recipient) name. |
| parcel_count | integer | Number of parcels at the stop. |
| custom_fields | object | Custom field values keyed by slot (custom1 - custom5). Only fields enabled in the workspace (and in the plan) are stored. |
| stop_duration | integer | Service duration at the stop, in seconds. |
| stop_priority | string | Stop priority, for example Normal, High, Urgent. |
| capacity_fields | object | Capacity values (integers) for load planning, keys capacity1 - capacity5. |
| customer_system_id | string | Your own identifier for the stop (for cross-referencing). |
| phone_country_code | string | Phone dialing code, for example 1. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"address"
],
"properties": {
"city": {
"type": "string",
"maxLength": 200,
"description": "City (overrides the geocoded value)."
},
"note": {
"type": "string",
"maxLength": 2000,
"description": "Free-text note shown to the driver."
},
"email": {
"type": "string",
"maxLength": 254,
"description": "Contact email."
},
"phone": {
"type": "string",
"maxLength": 40,
"description": "Contact phone number; non-digits are stripped by Upper."
},
"state": {
"type": "string",
"maxLength": 200,
"description": "State or region (overrides the geocoded value)."
},
"address": {
"type": "string",
"maxLength": 500,
"minLength": 1,
"description": "Street address of the stop (geocoded by Upper)."
},
"zipcode": {
"type": "string",
"maxLength": 40,
"description": "Postal code (overrides the geocoded value)."
},
"end_time": {
"type": "string",
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?$",
"description": "Latest service time (time window end), HH:MM or HH:MM:SS."
},
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Route to attach the stop to; omit for an unscheduled stop.",
"exclusiveMinimum": 0
},
"nick_name": {
"type": "string",
"maxLength": 100,
"description": "Short label for the stop."
},
"pin_color": {
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Map pin colour, hex like #FF6600."
},
"stop_type": {
"type": "string",
"maxLength": 50,
"description": "Stop type, for example Delivery or Pickup."
},
"start_time": {
"type": "string",
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?$",
"description": "Earliest service time (time window start), HH:MM or HH:MM:SS."
},
"company_name": {
"type": "string",
"maxLength": 200,
"description": "Company name for the stop."
},
"contact_name": {
"type": "string",
"maxLength": 200,
"description": "Contact (recipient) name."
},
"parcel_count": {
"type": "integer",
"maximum": 100000,
"minimum": 0,
"description": "Number of parcels at the stop."
},
"custom_fields": {
"type": "object",
"description": "Custom field values keyed by slot (custom1 - custom5). Only fields enabled in the workspace (and in the plan) are stored.",
"propertyNames": {
"type": "string",
"maxLength": 64,
"minLength": 1
},
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 2000
},
{
"type": "number"
},
{
"type": "boolean"
}
]
}
},
"stop_duration": {
"type": "integer",
"maximum": 86400,
"minimum": 0,
"description": "Service duration at the stop, in seconds."
},
"stop_priority": {
"type": "string",
"maxLength": 50,
"description": "Stop priority, for example Normal, High, Urgent."
},
"capacity_fields": {
"type": "object",
"properties": {
"capacity1": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity2": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity3": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity4": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity5": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
}
},
"description": "Capacity values (integers) for load planning, keys capacity1 - capacity5."
},
"customer_system_id": {
"type": "string",
"maxLength": 200,
"description": "Your own identifier for the stop (for cross-referencing)."
},
"phone_country_code": {
"type": "string",
"pattern": "^\\d{1,4}$",
"description": "Phone dialing code, for example 1."
}
}
}| end_time |
| string |
| Latest service time (time window end), HH:MM or HH:MM:SS. |
| route_id | integer | Move the stop to this route. |
| nick_name | string | Short label for the stop. |
| pin_color | string | Map pin colour, hex like #FF6600. |
| stop_type | string | Stop type, for example Delivery or Pickup. |
| start_time | string | Earliest service time (time window start), HH:MM or HH:MM:SS. |
| company_name | string | Company name for the stop. |
| contact_name | string | Contact (recipient) name. |
| parcel_count | integer | Number of parcels at the stop. |
| custom_fields | object | Custom field values keyed by slot (custom1 - custom5). Only fields enabled in the workspace (and in the plan) are stored. |
| stop_duration | integer | Service duration at the stop, in seconds. |
| stop_priority | string | Stop priority, for example Normal, High, Urgent. |
| capacity_fields | object | Capacity values (integers) for load planning, keys capacity1 - capacity5. |
| customer_system_id | string | Your own identifier for the stop (for cross-referencing). |
| phone_country_code | string | Phone dialing code, for example 1. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"stop_id"
],
"properties": {
"city": {
"type": "string",
"maxLength": 200,
"description": "City (only used when no address is passed)."
},
"note": {
"type": "string",
"maxLength": 2000,
"description": "Free-text note shown to the driver."
},
"email": {
"type": "string",
"maxLength": 254,
"description": "Contact email."
},
"phone": {
"type": "string",
"maxLength": 40,
"description": "Contact phone number; non-digits are stripped by Upper."
},
"state": {
"type": "string",
"maxLength": 200,
"description": "State or region (only used when no address is passed)."
},
"address": {
"type": "string",
"maxLength": 500,
"minLength": 1,
"description": "New street address (re-geocoded)."
},
"stop_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The stop to update.",
"exclusiveMinimum": 0
},
"zipcode": {
"type": "string",
"maxLength": 40,
"description": "Postal code (only used when no address is passed)."
},
"end_time": {
"type": "string",
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?$",
"description": "Latest service time (time window end), HH:MM or HH:MM:SS."
},
"route_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Move the stop to this route.",
"exclusiveMinimum": 0
},
"nick_name": {
"type": "string",
"maxLength": 100,
"description": "Short label for the stop."
},
"pin_color": {
"type": "string",
"pattern": "^#[0-9a-fA-F]{6}$",
"description": "Map pin colour, hex like #FF6600."
},
"stop_type": {
"type": "string",
"maxLength": 50,
"description": "Stop type, for example Delivery or Pickup."
},
"start_time": {
"type": "string",
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?$",
"description": "Earliest service time (time window start), HH:MM or HH:MM:SS."
},
"company_name": {
"type": "string",
"maxLength": 200,
"description": "Company name for the stop."
},
"contact_name": {
"type": "string",
"maxLength": 200,
"description": "Contact (recipient) name."
},
"parcel_count": {
"type": "integer",
"maximum": 100000,
"minimum": 0,
"description": "Number of parcels at the stop."
},
"custom_fields": {
"type": "object",
"description": "Custom field values keyed by slot (custom1 - custom5). Only fields enabled in the workspace (and in the plan) are stored.",
"propertyNames": {
"type": "string",
"maxLength": 64,
"minLength": 1
},
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 2000
},
{
"type": "number"
},
{
"type": "boolean"
}
]
}
},
"stop_duration": {
"type": "integer",
"maximum": 86400,
"minimum": 0,
"description": "Service duration at the stop, in seconds."
},
"stop_priority": {
"type": "string",
"maxLength": 50,
"description": "Stop priority, for example Normal, High, Urgent."
},
"capacity_fields": {
"type": "object",
"properties": {
"capacity1": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity2": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity3": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity4": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
},
"capacity5": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991
}
},
"description": "Capacity values (integers) for load planning, keys capacity1 - capacity5."
},
"customer_system_id": {
"type": "string",
"maxLength": 200,
"description": "Your own identifier for the stop (for cross-referencing)."
},
"phone_country_code": {
"type": "string",
"pattern": "^\\d{1,4}$",
"description": "Phone dialing code, for example 1."
}
}
}