Skip to main content
Glama
dragosh29

Spoke Dispatch MCP server

by dragosh29

Spoke Dispatch MCP server

An MCP server that lets Claude, ChatGPT and other MCP clients work with a Spoke Dispatch team (delivery route planning and driver dispatch, formerly Circuit for Teams): plans, stops, routes, drivers, depots and plan-optimization operations, and (when enabled) creating plans, importing stops, optimizing and distributing plans. It is built from Spoke's public API documentation and its published OpenAPI 3.1 spec (https://developer.dispatch.spoke.com/openapi-v1.json, "Spoke API" v1).

Once it's connected, a dispatcher can ask things like:

  • "How is today's Bristol plan going? Which stops have failed, and what is the ETA for the rest?"

  • "Where is Sam's route up to, and has it been started?"

  • "Find every stop for order A-1005, and the ones in Bath that were not attempted last week."

  • "Which drivers are paused, and which depot are they on?"

  • With writes enabled: "Create tomorrow's plan for Sam and Priya, import these 40 stops, optimize it, and when the operation is done, distribute it."

Tools

Tool

What it does

API calls

list_plans

Plans (one per working day) with start date, depot, optimization and distribution state, driver and route IDs and route overrides. Filters by exact title and a start-date range; token-paginated.

GET /plans

get_plan

One plan.

GET /plans/{planId}

list_plan_stops

Every stop of a plan: type (start/stop/end), route, position, delivery state and outcome, ETA, time window, packages, order references, service and payment-on-delivery data. Filters by the recipient's external ID.

GET /plans/{planId}/stops

search_stops

Full-text keyword search plus Spoke's SQL-like filter language across all stops, assigned and unassigned, with the documented sort fields.

GET /stops:search

list_routes

Routes (one driver's run) with stop count, driver, plan and state (distributed, started, completed, recipients notified, with timestamps).

GET /routes

get_route

One route.

GET /routes/{routeId}

list_route_stops

The stops of one route, same shape as list_plan_stops.

GET /routes/{routeId}/stops

list_drivers

Drivers with active status, depots and route overrides (working hours, vehicle, max stops). Filters by active status.

GET /drivers

get_driver

One driver.

GET /drivers/{driverId}

list_depots

Depots with their default route settings (start time, start and end address, round trip, time at stop, max stops, vehicle).

GET /depots

list_operations

Plan-optimization operations: done or not, who started them, target plan, result (stops optimized, stops skipped with reasons) or error. Filters by done and type.

GET /operations

get_operation

One operation, to poll after optimize_plan.

GET /operations/{operationId}

create_plan

Creates an empty plan for a date with optional drivers, depot and route overrides. Writes only.

POST /plans

import_stops

Batch-imports 1 to 100 stops into a writable plan using the API's own field names; reports the IDs created and the stops Spoke rejected with its reason, each identified by the external ID and first address line sent in that same call. Writes only.

POST /plans/{planId}/stops:import

optimize_plan

Starts optimizing a plan into routes; returns the operation to poll. Writes only.

POST /plans/{planId}:optimize

distribute_plan

Sends an optimized plan's routes to the drivers' apps. Marked destructive: it notifies real drivers and the API has no way to undo it. Writes only.

POST /plans/{planId}:distribute

Not covered on purpose: updating and deleting plans, stops, drivers, depots and members; creating stops one at a time; the live-plan endpoints (:liveCreate, :liveUpdate, :liveImport, :liveDelete, :reoptimize, :redistribute, :save); unassigned stops other than through search; custom stop property definitions; cancelling operations; members.

Related MCP server: delivery-mcp-server

Setup

Requires Node 18 or later.

npm install
npm run build

You need an API key for your Spoke Dispatch team, generated under Settings > Integrations > API. The API authenticates with HTTP Basic: the key is the username and the password is empty, and that is what this server sends (the spec also accepts the key as a Bearer token).

Claude Desktop: add this to claude_desktop_config.json:

{
  "mcpServers": {
    "spoke": {
      "command": "node",
      "args": ["/absolute/path/to/spoke-mcp/dist/index.js"],
      "env": { "SPOKE_API_KEY": "your-key" }
    }
  }
}

Claude Code:

claude mcp add spoke -e SPOKE_API_KEY=your-key -- node /absolute/path/to/spoke-mcp/dist/index.js

Variable

Required

Meaning

SPOKE_API_KEY

yes

Your API key, sent as the HTTP Basic username with an empty password.

SPOKE_ALLOW_WRITES

no

true to register create_plan, import_stops, optimize_plan and distribute_plan. Off by default.

SPOKE_BASE_URL

no

Defaults to https://api.spoke.com/public/v1. Used by the tests.

Safety defaults

  • Read-only unless SPOKE_ALLOW_WRITES=true. Read tools carry the MCP readOnlyHint annotation; distribute_plan is marked destructive because it pushes routes to real drivers and cannot be undone through the API.

  • Recipients are third parties. By default a stop's recipient block only says which fields exist (name, email, phone, external_id), the address is reduced to its locality (the part after the street line, with postal codes cut to their area part or dropped: UK BS7 8QH becomes BS7, an Irish Eircode D02 X285 becomes D02, a Canadian K1A 0A2 becomes K1A, a Dutch 1012 JS and any all-digit code such as a US ZIP 20500, 20500-0003, or a German, French or Australian code are dropped, so 2 Melbourne Road, Bristol, BS7 8QH, UK becomes Bristol, BS7, UK and 1600 Pennsylvania Ave NW, Washington, DC 20500, USA becomes Washington, DC, USA; coordinates and the Google place ID are left out), and the signee name, the location where the delivery was attempted, the proof-of-delivery photo and signature links and the recipient tracking link are withheld. The same applies to unassigned stops returned by search_stops. Everything is returned when the assistant explicitly asks (include_contact_details). Photo and signature URLs are passed through as links; nothing is ever downloaded.

  • Drivers are employees. Their email, phone number and their own start/end addresses are only returned with include_contact_details; names and display names are returned (minus any email or phone typed into them).

  • Plan and depot addresses (where routes start and end) are the team's own operating locations and are returned as stored.

  • In free text (plan, route and depot titles and names, driver display names, stop notes, driver and recipient notes and custom property values; seller names, products, package labels and Spoke's own error messages take the same code path but are not exercised by the tests) email addresses are replaced with [email redacted] and phone-number-like sequences with [phone redacted] by default. The phone match is a heuristic pattern covering UK national numbers (07700 900123, 020 7946 0958, (020) 7946 0958), +- and 00-prefixed international numbers (+447700900123, +1 415 555 0123, 0044 20 7946 0958) and North-American 10-digit national numbers ((415) 555-0123, 415-555-0123, 415.555.0123, 4155550123), each with spaces, dots or hyphens between the groups; the tests exercise all of these forms. A 7-digit local number without an area code, and formats of other countries written without a leading 0 or +, are not matched. Other digit strings that happen to look like one of those shapes (a 9-11 digit string starting with 0, a 10-digit string starting with 2-9) are redacted too, while Spoke IDs, barcodes, dates, epoch timestamps and order references such as A-1002 are left alone; the raw text is available with include_contact_details.

  • The address summary is a heuristic: it takes addressLineTwo (or the full address after its first comma) as the locality, so what it contains depends on how Spoke split the address into lines. When Spoke stores the street in addressLineTwo (for instance Flat 3 in line one and 2 Melbourne Road, Bristol, BS7 8QH, UK in line two) the summary contains the house number and street; the tests show this case. Postal codes in formats other than the ones listed above are only removed when they are all digits.

  • IDs are checked before any call is made: the spec's path parameters are [a-zA-Z0-9---_]{1,50} (letters, digits, - and _), and every tool accepts either that bare form or the prefixed form the API uses in bodies and responses (plans/<id>). Dates must be YYYY-MM-DD and a real calendar date (2026-02-30 and 2026-13-01 are refused locally); create_plan additionally requires the year the request schema documents (2000 to 2100). Times must be HH:MM. Both are converted to the spec's {year, month, day} and {hour, minute} objects.

  • import_stops validates every stop locally against the documented request shape (unknown fields, an empty address and more than 100 stops are refused before any call) and converts HH:MM windows and bare driver IDs to the documented forms. Its failure list has no include_contact_details switch: for each stop Spoke rejected it returns Spoke's reason plus the external ID and first address line that the caller sent in that same call (the API echoes the whole stop back rather than its position in the array), with the free-text redaction applied to the reason and the address line; the echoed recipient name, email and phone are not returned.

  • Rate limits, as Spoke documents them ("On Rate-Limiting" in the spec): read endpoints 10 requests per second; write endpoints (POST, PATCH, DELETE) 5 per second, driver creation 1 per second; the stop batch imports 100 per 10 minutes with at most 30 per minute; the driver batch import 2 per minute; plan optimization and re-optimization 100 per 10 minutes with at most 30 per minute; bursts are tolerated briefly, sustained high rates are rejected, and a client that keeps retrying rejected requests keeps being rejected. Spoke recommends exponential backoff with a random delay and documents no Retry-After header. This server spaces reads 120 ms apart, writes 250 ms apart and imports and optimizations 2.1 s apart. A 429 is retried at most twice for any method (a rejected request was not processed), waiting for Retry-After when one is sent (whole or fractional seconds, or an HTTP-date) and otherwise 1 s then 2 s plus up to 300 ms of jitter. Each wait is capped at 10 seconds so a tool call stays under the MCP client's default 60-second request timeout: if Spoke asks for a longer wait the call gives up at once and the message says how long to wait.

  • 502, 503 and 504 are retried the same way for GET only; when all three attempts fail the error says the service may be unavailable and to try again in a few minutes, without the gateway's HTML. The four write tools are never retried after a gateway error, because the request may already have been processed and a retry could create a plan, import stops, or notify drivers twice; the error names the read tool to check with first (list_plans, list_plan_stops, list_operations, get_plan).

  • Spoke documents no idempotency keys, so none are sent.

  • A 200 whose body is not JSON (a proxy or a login page in the way) is reported as an error naming SPOKE_BASE_URL, never as an empty list.

  • A rejected API key produces a message that says which variable to fix and where keys come from. The documented 403 for a plan or route older than the subscription's delivery-history period (plan_inaccessible, route_inaccessible) is explained; 404s carry Spoke's message (Plan not found, Route not found, Driver not found, The operation was not found.); 409s pass on Spoke's message and code (plan_not_writable, plan_already_optimized, plan_optimization_in_progress, plan_not_optimized, plan_already_distributed are exercised; no_drivers_available takes the same path); 400 and 412 pass on the message, code and offending parameter, and 410 and 422 take the same path without being exercised.

Tests

npm test

The test suite:

  1. Validates every fixture record with Ajv (JSON Schema 2020-12, as the spec is OpenAPI 3.1) against the component schemas in Spoke's published spec (planSchema, stopSchema, unassignedStopSchema, routeSchema, driverSchema, depotSchema, operationSchema), all of which set additionalProperties: false and mark nearly every field required, with negative controls. The spec is downloaded from developer.dispatch.spoke.com/openapi-v1.json to spec.json on the first run.

  2. Starts a local mock of the API under /public/v1 that serves those fixtures with the documented pageToken/nextPageToken/maxPageSize pagination (including each endpoint's maximum page size and the search's exclusiveMaximum of 20), the documented filter.* parameters, Basic-auth 401s, the documented 403, 404 and 409 bodies, a subset of the stop-search filter language, and answers the first GET /depots with a 429. The mock's list, detail, search, create, import, optimize and distribute responses and its error responses are validated against the spec's response schemas. (One quirk: the search's documented 400 is a oneOf whose generic first branch also matches every specific branch, so nothing can satisfy it; the mock's answer is checked against the "Invalid filter string" branch.)

  3. Starts the built server and drives it over stdio with the official MCP client: 25 checks covering every tool, tool annotations, token pagination across pages to the null token with whole pages and a continuation that repeats the original filters, every documented filter passed through exactly (filter.title, filter.startsGte, filter.startsLte, filter.externalId, filter.active, filter.done, filter.type, and the search's keyword, filter, sortField, sortOrder), a page size of 19 on the search and of 2 (its documented minimum) when one result is asked for, recipient, address, proof-of-delivery, tracking-link and free-text redaction by default and their return on request, the address summary on UK, Irish, US, Canadian, Dutch, German and Australian postal codes and on a street stored in addressLineTwo, the phone pattern on UK, international and North-American forms with negative controls, the POST /plans and POST .../stops:import bodies validated against the spec's request schemas, local refusal of dates that are not real calendar dates or outside the documented 2000-2100 plan years, local refusal of an empty address, an unknown stop field and more than 100 stops, a partially failed import reported with the redacted reason, external ID and address line, the documented 409s, ID validation before any call and the documented 404 and 403 messages, the 429 retry waiting for a Retry-After of 2 s (a wait the no-header fallback cannot produce) and in the fractional and HTTP-date forms, exponential backoff without the header, giving up after three attempts and at once above the cap, a 429 on a write retried once, a 502 retried for GET only and never for any of the four writes, a GET failing three times reported without the gateway HTML, a non-JSON 200 reported as an error, the write gate with the variable unset and set to false, and that every request used Basic base64(key:), Content-Type: application/json on writes, and a documented method and path.

The suite makes 77 requests against the mock and takes about 40 seconds, most of it deliberate waits in the retry checks.

Status

This is a working prototype. It has not yet been run against the live API, because it was built without a Spoke Dispatch account. Everything below is taken from the published spec and should be confirmed on a real account:

  • Whether API keys are available during the free trial, and whether a Basic header with an empty password (base64("<key>:")) is accepted exactly as the spec describes; the Bearer form is the documented fallback.

  • The real nextPageToken values and whether a continuation must repeat maxPageSize unchanged (the server repeats every query parameter, as the spec says to). What the API answers for a stale or foreign page token (the spec documents a 400 with param: pageToken for the search only).

  • GET /stops:search: the spec documents maxPageSize with exclusiveMaximum: 20 and a default of 20, which contradict each other; the server sends 19. Whether keyword and filter may be combined, the exact filter grammar the live API accepts (the mock implements a subset), how fresh the search index is, and whether sortField must be one of the ten documented fields.

  • The filter parameter spelling: the spec documents both ?filter[title]= and ?filter.title=; the server sends the dot form.

  • How addresses are split into address, addressLineOne and addressLineTwo on real stops, which decides what the default locality summary contains. Real coordinates are also left out by default.

  • Whether stopSchema.route is really the full embedded route object on list responses (as the schema says) and whether deliveryInfo is null or an unattempted record before an attempt.

  • POST /plans: the accepted date range for starts ("does not accept dates that are too far in the future or past"; the server only enforces the schema's 2000-2100), whether routeOverrides.optimizationSettings.objective accepts anything other than the single documented value distribute_services, and whether drivers must already belong to the plan's depot (the migration guide says so).

  • POST /plans/{planId}/stops:import: the wording of the per-stop failure messages (the mock's "Address could not be geocoded" is a placeholder), whether the API geocodes from text fields alone, whether customProperties keys are property IDs as documented, and what a partially failed import returns beyond success and failed.

  • POST .../:optimize and :distribute: whether the 409 bodies match the spec's enums exactly, how long optimization takes, and whether distribution notifies drivers immediately.

  • The 401 body (the spec gives it only a description; the mock answers {"message": "Unauthorized"}) and whether any error message ever echoes request data such as a recipient's email. The server applies the free-text redaction to every error message; the tests exercise it on a per-stop import failure message, not on the message of an HTTP error response.

  • How addresses outside the UK, Ireland, Canada and the Netherlands are formatted on real stops; a postal code in another format that is not all digits stays in the default summary.

  • Whether Spoke sends Retry-After on 429 (nothing is documented), and whether a rate-limited write is indeed never processed; the server assumes so and retries a 429 on a write once.

  • How many requests per second the API really tolerates from one key; the spacing here follows the documented limits with a margin.

Going to production

This version runs locally over stdio, with the dispatcher's own API key. For teams to connect from claude.ai or ChatGPT without handling keys, the next step is a remote server (Streamable HTTP) behind OAuth, hosted by Spoke, and then a listing in the Claude and ChatGPT connector directories.

Licence

MIT. Built by Alexandru DragoČ™ (alexandru.dragos96@gmail.com) with an AI agent (Claude) working under his direction.

Available Tools

12 tools
get_driverGet a driverA
Read-only

One driver: name, active status, depots and route overrides. Email, phone and start/end address only with include_contact_details.

ParametersJSON Schema
NameRequiredDescriptionDefault
driver_idYesDriver ID (drivers/<id> or the bare <id>)
include_contact_detailsNoInclude the driver's email address, phone number and full start/end addresses

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds one useful behavioral detail — that contact fields are gated behind include_contact_details — but says nothing about errors, permissions, or what happens with an unknown ID beyond what the schema implies.

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

Conciseness5/5

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

Two tight sentences with zero filler; the returned-field list is front-loaded and the conditional-contact caveat follows naturally. Every clause carries information.

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

Completeness4/5

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

With no output schema, the description correctly compensates by listing the returned fields, and the conditional contact-detail rule is stated. It stops short of describing error behavior or the driver_id format nuances, but it is sufficient for correct invocation.

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

Parameters3/5

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

Schema coverage is 100%, so both parameters are already documented, including the include_contact_details effect. The description restates that effect in different terms (email/phone/start-end address) without adding syntax or edge cases, so it earns the baseline 3 rather than more.

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 description names the resource (a single driver) and enumerates the returned fields (name, active status, depots, route overrides), which implicitly distinguishes it from list_drivers and get_route. It lacks an explicit verb like 'retrieve', but the singular 'One driver' clearly signals a single-record fetch versus a listing.

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

Usage Guidelines3/5

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

Usage is only implied: the singular framing suggests fetching one known driver rather than browsing, but no alternative (e.g., list_drivers for enumeration) is named and no precondition is stated. Adequate for a simple read but leaves routing to sibling tools to inference.

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

get_operationGet an operationA
Read-only

One operation, to poll a plan optimization started with optimize_plan: done, timestamps, and the result or error once finished.

ParametersJSON Schema
NameRequiredDescriptionDefault
operation_idYesOperation ID (operations/<id> or the bare <id>)

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, covering the safety profile. The description adds valuable behavioral context beyond annotations: it is a polling tool and returns done, timestamps, and result/error once finished. It does not mention auth requirements or rate limits, but the key operational behavior is disclosed.

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

Conciseness5/5

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

One compact sentence, front-loaded with the resource (one operation) and its primary use case, with no filler or repetition.

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

Completeness4/5

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

No output schema exists, so the description usefully describes the return lifecycle (done, timestamps, result/error). With one fully documented required parameter and a clear polling purpose, the definition is nearly complete, though it could explicitly distinguish itself from list_operations.

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

Parameters3/5

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

Schema coverage is 100%, and the single operation_id parameter is fully documented in the schema with its pattern and accepted format. The description adds no additional syntax or constraints beyond what the schema already provides, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (get/poll) and resource (one operation), and ties it to a known originating workload (optimize_plan). This clearly distinguishes it from sibling list_operations, which returns many operations.

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?

Identifies the polling scenario after optimize_plan, which tells the agent when to call it. It does not explicitly exclude list_operations or state when-not to use this tool, but the context is clear.

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

get_planGet a planB
Read-only

One plan: start date, depot, optimization and distribution state, driver IDs, route IDs and route overrides.

ParametersJSON Schema
NameRequiredDescriptionDefault
plan_idYesPlan ID (plans/<id> or the bare <id>)
include_contact_detailsNoInclude email addresses and phone numbers typed into the title and route override addresses

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so safety is covered. The description adds useful context about what the payload contains (state, driver/route IDs, overrides), but says nothing about the sensitivity of contact data exposed by include_contact_details or how much data a full plan returns.

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

Conciseness4/5

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

A single front-loaded sentence with no filler; the colon-list of returned fields is efficient. It is a field dump rather than prose, which is acceptable but slightly dense.

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

Completeness4/5

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

With no output schema, the description usefully summarizes the returned payload shape, compensating for the missing return documentation. Combined with annotations and full schema coverage, an agent has enough to call it correctly, though the contact-details flag's effect is never explained.

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

Parameters3/5

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

Schema description coverage is 100%, so both parameters are documented in the schema, including the plans/<id> prefix pattern. The description does not add any meaning about include_contact_details, which is the one parameter with privacy implications, so it stays at the baseline.

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 description names the resource ('one plan') and enumerates the fields it carries, which clearly separates it from the sibling list_plans and the route/stop getters. The verb is only implied by 'One plan', so it is clear but not stated as explicitly as a 'Get X by ID' phrasing would be.

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

Usage Guidelines2/5

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

There is no guidance on when to call this versus list_plans or get_route, and no mention of prerequisites such as needing a plan_id from list_plans. Usage must be inferred entirely from the name and schema.

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

get_routeGet a routeA
Read-only

One route with its stop count, driver, plan and state. Use list_route_stops for the stops.

ParametersJSON Schema
NameRequiredDescriptionDefault
route_idYesRoute ID (routes/<id> or the bare <id>)
include_contact_detailsNoInclude email addresses and phone numbers typed into the title

TDQS

A3.8/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds the useful disclosure of what fields the record contains, but says nothing about the effect of include_contact_details (PII exposure), auth requirements, or what happens when the ID is unknown.

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

Conciseness5/5

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

Two short sentences, zero filler, and the returned-content summary is front-loaded ahead of the sibling redirect. Every clause earns its place.

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

Completeness4/5

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

With no output schema, the description usefully summarizes the returned record shape, which is exactly the burden it must carry. It leaves a small gap around the PII-flagging parameter and error behavior, but for a simple two-parameter read tool it is close to sufficient.

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

Parameters3/5

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

Schema description coverage is 100%, with both route_id (including the routes/<id> pattern) and include_contact_details documented in-schema. The description adds no syntax, default, or format detail beyond the schema, so the baseline of 3 applies even though it hints at the returned field set.

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 description names the resource (a route) and enumerates what comes back — stop count, driver, plan, state — which is far more specific than the title 'Get a route'. It also names a sibling, but for the stops sub-resource rather than for the retrieval itself, so differentiation from get_plan/get_driver is only partial.

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

Usage Guidelines4/5

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

It explicitly routes the agent to list_route_stops for stop-level data, which is a genuine when-to-use-this-vs-alternative signal. It stops short of stating any exclusions or prerequisites (e.g., that a route_id must be known first), so it is clear context without full when/when-not coverage.

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

list_depotsList depotsB
Read-only

Depots (the team's operating bases) with their default route settings: start time, start and end address, round trip, time at stop, max stops, vehicle type.

ParametersJSON Schema
NameRequiredDescriptionDefault
page_tokenNonext_page_token from a previous call, to continue the same list
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
include_contact_detailsNoInclude email addresses and phone numbers typed into depot names or addresses

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare this is a read-only, open-world operation, so the safety profile is covered. The description adds useful context by enumerating the depot fields returned, but it does not discuss pagination behavior, authentication needs, or the effect of include_contact_details, which are handled in the schema.

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

Conciseness4/5

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

The description is a single, dense sentence with no wasted words. It front-loads the resource concept and then lists the returned fields, though it is a noun phrase rather than a full action-oriented statement.

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

Completeness4/5

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

For a read-only list tool with rich schema annotations and fully described parameters, the description appropriately summarizes the returned depot data. It does not need to repeat pagination or return-format details already covered by the schema.

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

Parameters3/5

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

Schema description coverage is 100% and all three parameters are fully documented in the input schema. The description adds no parameter-level guidance, so the baseline score of 3 is appropriate.

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 description identifies the resource precisely as 'Depots (the team's operating bases)' and lists the default route settings returned. It is clear what the tool exposes, but it does not name the list operation or distinguish itself from sibling tools like list_routes or list_plans beyond the resource type.

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

Usage Guidelines2/5

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

There is no guidance on when to use this tool versus alternatives. The description does not mention any context, exclusions, or sibling tools, leaving usage entirely implied by the resource name.

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

list_driversList driversA
Read-only

Drivers on the team with their active status, depots and route overrides (working hours, vehicle, max stops). Email, phone and a driver's own start/end address are only returned with include_contact_details.

ParametersJSON Schema
NameRequiredDescriptionDefault
activeNoOnly active (true) or only paused (false) drivers; paused drivers are not assigned to routes (the API's filter.active)
page_tokenNonext_page_token from a previous call, to continue the same list
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
include_contact_detailsNoInclude driver email addresses, phone numbers and full start/end addresses

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds real value beyond them by disclosing that email, phone and start/end address are suppressed by default and only surfaced via include_contact_details — a PII exposure trait not visible in the annotations.

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

Conciseness5/5

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

Two compact sentences, no boilerplate, with the return contents front-loaded and the conditional PII caveat immediately after. Every clause carries information.

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

Completeness4/5

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

With no output schema, the description usefully enumerates the returned shape and the conditional PII fields. Pagination and filtering behavior live in the 100%-covered schema, so the only omission is any hint that results are paged at all.

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. The description nonetheless adds the opt-in semantics for include_contact_details — that those fields are returned *only* with the flag — which sharpens the schema's plain field list into a default-behavior statement.

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?

Specific verb+resource ("Drivers on the team") followed by the exact payload it returns: active status, depots, route overrides. It does not explicitly distinguish itself from the sibling get_driver, so it falls short of the 5 bar that requires naming the alternative.

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

Usage Guidelines3/5

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

Usage is only implied through the include_contact_details conditional. There is no statement of when to call this instead of get_driver, nor any prerequisite or exclusion, so the agent must infer routing from the conventional list/get naming.

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

list_operationsList operationsB
Read-only

Long-running operations (currently only plan_optimization) with whether they are done, who started them, the target plan and the result (stops optimized, stops skipped with reasons, or an error).

ParametersJSON Schema
NameRequiredDescriptionDefault
doneNoOnly finished (true) or only running (false) operations (the API's filter.done)
typeNoOnly operations of this type (the API's filter.type)
page_tokenNonext_page_token from a previous call, to continue the same list
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds useful context about result shape (stops optimized, stops skipped with reasons, or an error), but says nothing about pagination behavior despite page_token/max_results existing, nor about result limits.

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

Conciseness4/5

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

A single dense sentence that front-loads the resource and then the returned fields. Efficient with no wasted preamble, though the parenthetical list is slightly run-on.

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

Completeness4/5

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

With no output schema, the description carries the return-value burden and does describe the result contents (optimized/skipped counts, errors). Combined with a fully documented schema, this is largely complete; only pagination/continuation behavior is left unstated.

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

Parameters3/5

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

Schema description coverage is 100%, so all four parameters (done, type, page_token, max_results) are already documented in the schema with API filter mappings. The description adds no additional parameter semantics beyond noting the single valid operation type, making the baseline 3 appropriate.

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?

States a specific resource (long-running operations) and enumerates the payload (done status, starter, target plan, result), so an agent knows what it retrieves. It does not differentiate itself from the get_operation sibling, which covers the same domain, so it stops short of a 5.

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

Usage Guidelines2/5

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

No when-to-use guidance and no mention of the alternative get_operation for fetching a single operation. The agent must infer that this is the bulk/list counterpart, and nothing tells it when listing is preferable.

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

list_plansList plansA
Read-only

Plans (one per working day, each with its drivers and routes) in the order the API returns them. Filter by an exact title and/or a start-date range. Plan titles are free text: email addresses and phone numbers in them are redacted unless include_contact_details is true.

ParametersJSON Schema
NameRequiredDescriptionDefault
titleNoExact plan title (the API's filter.title; no partial match)
starts_toNoPlans starting on or before this date, YYYY-MM-DD (filter.startsLte)
page_tokenNonext_page_token from a previous call, to continue the same list
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
starts_fromNoPlans starting on or after this date, YYYY-MM-DD (filter.startsGte)
include_contact_detailsNoInclude email addresses and phone numbers typed into plan titles and route override addresses

TDQS

A3.7/5.0
Behavior4/5

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

Annotations already establish readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuinely non-obvious behavior: plan titles are free text and email addresses/phone numbers are redacted unless include_contact_details is true. It does not cover pagination behavior, but the added redaction context is substantive.

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

Conciseness4/5

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

Three tight sentences: resource and ordering first, filtering second, redaction caveat last. No filler, though the redaction sentence restates part of the schema description.

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

Completeness4/5

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

With no output schema, the description usefully notes the return ordering, and the schema fully documents pagination via page_token/max_results. It leaves empty-result and maximum-page behavior unstated, but nothing critical for a correct call is missing.

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

Parameters3/5

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

Schema description coverage is 100% and each parameter is documented with its API filter mapping (filter.title, filter.startsLte, next_page_token), so the schema does the heavy lifting. The description restates the include_contact_details redaction rule rather than adding new parameter-level syntax or format detail, so baseline 3 is correct.

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 description states the resource ('Plans, one per working day, each with its drivers and routes') and the ordering, so an agent knows exactly what comes back. It is clear but does not explicitly differentiate itself from siblings like get_plan or list_plan_stops, which a 5 would require.

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

Usage Guidelines3/5

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

It states which filters are available ('Filter by an exact title and/or a start-date range'), which implies when to use it, but gives no explicit when-not guidance or routing to alternatives such as get_plan for a single plan.

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

list_plan_stopsStops of a planA
Read-only

Every stop of one plan with its type (start/stop/end), route, position, delivery state and outcome, ETA, time window and packages. By default recipients are withheld, addresses are summarised to the locality, and proof-of-delivery links, signee names and recipient tracking links are left out; set include_contact_details to get them.

ParametersJSON Schema
NameRequiredDescriptionDefault
plan_idYesPlan ID (plans/<id> or the bare <id>)
page_tokenNonext_page_token from a previous call, to continue the same list
external_idNoOnly the stop(s) whose recipient.externalId equals this value exactly (the API's filter.externalId)
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
include_contact_detailsNoInclude recipient name, email, phone and external ID, the full address with coordinates, signee names, proof-of-delivery photo and signature links, the tracking link, and unredacted notes

TDQS

A3.9/5.0
Behavior4/5

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

Annotations only declare readOnlyHint and openWorldHint, so the description carries the meaningful behavioral burden and does it well: it discloses exactly what is redacted by default (recipients withheld, addresses reduced to locality, POD links, signee names, tracking links omitted) and what the opt-in flag restores. What it does not mention is pagination behavior or how much data a large plan returns, which is a modest gap for a list tool.

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

Conciseness4/5

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

Two sentences, front-loaded with the resource and its returned fields, followed by the visibility behavior. The first sentence is a long enumeration but every listed field is genuinely useful for deciding whether this tool answers the agent's question; no filler or restatement of the name.

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

Completeness4/5

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

For a read-only, fully-documented, single-resource list tool with no output schema, the description covers the essentials: what comes back, what is hidden by default, and how to unlock it. Only pagination/volume expectations are unaddressed, which the page_token schema field partially covers.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents plan_id, page_token, external_id, max_results and include_contact_details thoroughly. The description's only added semantic layer is framing include_contact_details as a privacy/redaction toggle rather than a plain field list, which duplicates much of the schema text. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource combination ('every stop of one plan') and then enumerates the returned attributes (type, route, position, delivery state, outcome, ETA, time window, packages). The 'one plan' scoping plus the field list lets an agent separate it from list_route_stops and search_stops 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 Guidelines3/5

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

The description makes the intended scope clear (stops belonging to a single plan) and explains the default-vs-opt-in visibility tradeoff, which is effectively usage guidance for the include_contact_details toggle. However, it never names an alternative or states when to prefer list_route_stops, search_stops, or get_plan instead, so routing between siblings is left to inference.

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

list_routesList routesB
Read-only

Routes (one driver's run within a plan) with stop count, driver, plan and state (distributed, started, completed, recipients notified, with timestamps).

ParametersJSON Schema
NameRequiredDescriptionDefault
page_tokenNonext_page_token from a previous call, to continue the same list
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
include_contact_detailsNoInclude email addresses and phone numbers typed into route titles

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds useful context about what a route is and the enumerated states with timestamps, but it does not disclose behavioral traits such as pagination behavior, permission requirements, or the PII exposure implied by the include_contact_details parameter.

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

Conciseness5/5

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

The description is a single, front-loaded sentence that defines the resource and its returned fields without any wasted words. Every element earns its place.

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

Completeness4/5

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

With no output schema, the description carries the burden of explaining return values. It lists several key fields (stop count, driver, plan, state with timestamps), which is helpful, but it does not fully describe the route object structure, sorting, or filtering behavior. Given the schema already covers pagination and the optional contact details flag, the description is largely complete.

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

Parameters3/5

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

Schema description coverage is 100%, so all three parameters are fully documented in the schema. The description does not add any meaning beyond what the schema provides, making the baseline score of 3 appropriate.

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 description defines a route as 'one driver's run within a plan' and lists the data it returns (stop count, driver, plan, state), which makes the resource and operation clear. It does not explicitly differentiate from the singular sibling get_route or name alternatives, so it falls short of a 5.

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

Usage Guidelines2/5

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

There is no guidance on when to use this tool versus get_route or the other list tools, nor any mention of prerequisites or exclusions. The description provides only a data definition, not usage context.

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

list_route_stopsStops of a routeA
Read-only

The stops of one route (one driver's run) in the order the API returns them, with delivery state and outcome, ETA, time window and packages. By default recipients are withheld, addresses are summarised to the locality, and proof-of-delivery links, signee names and recipient tracking links are left out; set include_contact_details to get them.

ParametersJSON Schema
NameRequiredDescriptionDefault
route_idYesRoute ID (routes/<id> or the bare <id>)
page_tokenNonext_page_token from a previous call, to continue the same list
external_idNoOnly the stop(s) whose recipient.externalId equals this value exactly (the API's filter.externalId)
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
include_contact_detailsNoInclude recipient name, email, phone and external ID, the full address with coordinates, signee names, proof-of-delivery photo and signature links, the tracking link, and unredacted notes

TDQS

A3.9/5.0
Behavior4/5

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

Annotations only declare readOnlyHint and openWorldHint, so the description carries the rest. It meaningfully adds that recipients are withheld, addresses are reduced to locality, and PoD links/signee names/tracking links are omitted by default, plus the exact flag that reverses this. That is substantive behavioral disclosure beyond the annotations, though pagination behavior is left to the schema.

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

Conciseness5/5

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

Two sentences, front-loaded with what is returned and followed by the default-vs-override behavioral note. No filler, and each clause carries distinct information.

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

Completeness5/5

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

With no output schema, the description still conveys return contents (delivery state and outcome, ETA, time window, packages) and the default redaction posture. Combined with 100% schema coverage, an agent has everything needed to select and call it correctly.

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

Parameters3/5

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

Schema description coverage is 100%, so route_id, page_token, external_id, max_results and include_contact_details are already documented at the schema level. The prose reinforces include_contact_details and the default redaction but adds little parameter meaning beyond what the schema text provides; baseline 3 applies.

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?

States a specific verb+resource (the stops of one route) and narrows scope to a single driver's run in API-returned order, which separates it from the broader list_routes and search_stops. However it does not explicitly name the closest sibling list_plan_stops, so an agent must infer the route-vs-plan distinction.

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

Usage Guidelines3/5

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

Usage is implied by the scoping phrase 'one route (one driver's run)' but there is no explicit when-to-use versus search_stops, list_plan_stops or get_route, and no stated prerequisites. The defaults paragraph explains behavior rather than alternatives, leaving selection logic to inference.

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

search_stopsSearch stopsA
Read-only

Full-text search across all stops (assigned and unassigned) within the team's data retention, by keyword and/or the API's filter language, e.g. deliveryInfo.state = "failed_not_home" and createdAt >= "2026-09-01T00:00:00Z" or address.address ~= "Bristol". Filterable fields include planId, routeId, type, activity, notes, address., recipient.name/email/phone/externalId, deliveryInfo.state/attempted/succeeded/attemptedAt, orderInfo., barcodes, packageLabel, createdAt, arrivalAt and customProperties.. String comparisons with >, >=, <, <= work on ISO-8601 dates only. The search index lags the live data slightly, so a stop created seconds ago may not be found yet.

ParametersJSON Schema
NameRequiredDescriptionDefault
filterNoFilter expression in Spoke's SQL-like syntax (sent as-is, the API validates it)
keywordNoKeywords, fuzzy-matched across the stops' text fields
page_tokenNonext_page_token from a previous call, to continue the same list
sort_fieldNoSort field; relevance when omitted
sort_orderNoSort direction (the API's default is asc)
max_resultsNoMinimum number of records to return; whole pages are returned, so a few more may come back
include_contact_detailsNoInclude recipient details, full addresses, proof-of-delivery links, tracking links and unredacted notes

TDQS

A4.1/5.0
Behavior4/5

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

Annotations only cover readOnly and openWorld; the description adds genuinely useful behavior: index lag means recently created stops may be missing, results are bounded by the team's data retention, and string range operators work on ISO-8601 dates only. No output format or pagination behavior is described, but the freshness caveat is real value beyond annotations.

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

Conciseness4/5

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

The opening clause front-loads what the tool does and the freshness caveat is a well-placed closing sentence. The long inline field enumeration is dense but each element is actionable; only minor tightening possible.

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

Completeness4/5

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

With no output schema, the description correctly does not attempt return values, and it supplies the two things an agent most needs to call it correctly: filter syntax and the indexing-lag caveat. Pagination is covered only by the schema's page_token description, so completeness is good but not total.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3; the description goes further by documenting the filter grammar with concrete examples, enumerating filterable fields (planId, routeId, address.*, deliveryInfo.state, etc.), and stating the ISO-8601 constraint on comparison operators. It does not add much on sort, page_token, or max_results beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Full-text search across all stops') and immediately scopes it ('assigned and unassigned', 'within the team's data retention'), which is exactly what separates it from the scoped siblings list_route_stops and list_plan_stops.

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

Usage Guidelines3/5

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

Usage is implied by the broad 'all stops' scope and the two worked filter examples, but no alternative is named and there is no guidance on keyword vs. filter, or when a scoped list_* call would be preferable. Adequate but leaves routing to inference.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 12 tool updatesv0.1.0
    • First observedget_driver
    • First observedget_operation
    • First observedget_plan
    • First observedget_route
    • First observedlist_depots
    • First observedlist_drivers
    • First observedlist_operations
    • First observedlist_plan_stops
    • First observedlist_plans
    • First observedlist_route_stops
    • First observedlist_routes
    • First observedsearch_stops

TDQS

A3.8/5.0

Scored across 12 tools

Disambiguation5/5

Each tool has a distinct scope: get_* retrieves a single entity, list_* retrieves collections, list_plan_stops and list_route_stops differ by parent scope, and search_stops provides cross-cutting full-text search. Overlaps between get_route and list_routes (or get_plan and list_plans) are cardinality differences, not ambiguities.

Naming Consistency5/5

All tool names use consistent snake_case with a clear verb_noun pattern: get_route, list_plans, get_plan, list_plan_stops, search_stops, etc. No mixed conventions or confusing verb choices.

Tool Count5/5

The 12 tools are well-scoped: each covers a distinct resource and action (plans, routes, stops, drivers, depots, operations) without obvious filler or duplication. This is an appropriate size for the dispatch domain.

Completeness3/5

The surface covers read access to plans, routes, stops, drivers, depots, and operations, but has no mutation or lifecycle tools (create/update/delete for core entities). Crucially, get_operation references optimize_plan as the source of operations, yet no optimize_plan tool is provided, creating a dead end for a key workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers