Skip to main content
Glama

Server Details

Location & routing intelligence for AI agents — geocoding, truck routing, traffic, weather, and place search.

Ownership verified
Status
Healthy
Uptime
85.9% over 56 days
OAuth
Works in Glama
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A4.1/5.0

Scored across 19 tools

Disambiguation5/5

Tools are differentiated by input type, output type, and use case: forward/reverse/structured/batch geocoding, named intersection resolution, place-ID lookup, routing, matrix, isochrone, map matching, trace attributes, live traffic, weather, and admin operations are all clearly scoped. Overlaps like map_match vs trace_attributes and directions vs distance_matrix are explicitly contrasted in the descriptions.

Naming Consistency3/5

All names are snake_case, but the set mixes verb_noun (search_places, resolve_intersection), noun_verb (batch_geocode, geofence_contains, place_get, trace_attributes), and bare noun phrases (directions, isochrone, quota, traffic, weather). The names remain readable and descriptive, but there is no single predictable naming pattern.

Tool Count4/5

19 tools is slightly above the typical 3–15 range, but the server covers a broad geospatial platform spanning geocoding, routing, POI search, traffic, weather, geofencing, fleet tracing, and quota/API-key management. Most tools have a distinct capability, so the count is reasonable though heavy.

Completeness4/5

The surface covers core geospatial workflows well: forward/reverse/structured/batch geocoding, intersection and place lookup, routing, matrices, isochrones, map matching, trace attributes, road snapping, place discovery, POI search, geofence containment, traffic, weather, and admin quota/key operations. Minor gaps remain, such as route optimization/multi-stop sequencing and geofence management beyond containment testing.

Available Tools

19 tools
batch_geocodeA
Read-onlyIdempotent
Inspect

Geocode multiple addresses in one request with structured per-record results. Use for bulk operations instead of repeated single geocode calls. Max 50 per batch.

ParametersJSON Schema
NameRequiredDescriptionDefault
addressesYesArray of addresses to geocode (max 50 per batch)

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
display_hintNo

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already provide readOnlyHint, openWorldHint, and idempotentHint, reducing the burden on the description. The description adds useful behavioral context by noting 'structured per-record results,' which indicates the response format for individual addresses, and reiterates the 'Max 50 per batch' limit. It doesn't specify error handling for partial failures, but with annotations covering safety, this is adequate.

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 two concise sentences: the first states the core purpose, the second gives usage guidance and the batch limit. No wasted words, making it efficiently front-loaded and easy to parse.

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

Completeness5/5

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

For a simple batch tool with one parameter, an output schema, and strong annotations, the description is complete. It covers the key operational constraints (bulk usage, max batch size, per-record results) without needing to elaborate on return values, which are presumably documented in the output 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%: the single 'addresses' parameter is fully described as 'Array of addresses to geocode (max 50 per batch).' The tool description repeats this limit and doesn't add any additional semantic detail beyond what the schema already provides, so it meets the baseline for high schema coverage.

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?

The description clearly states the tool's function: 'Geocode multiple addresses in one request with structured per-record results.' It uses a specific verb ('geocode') and resource ('multiple addresses'), and distinguishes itself from the sibling 'geocode' tool by emphasizing batch processing.

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

Usage Guidelines5/5

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

The description explicitly directs use: 'Use for bulk operations instead of repeated single geocode calls.' This provides both a when-to-use (bulk) and a when-not-to-use (as a substitute for repeated single calls), clearly differentiating it from the alternative geocode tool.

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

directionsA
Read-onlyIdempotent
Inspect

Generate routes, ETAs, and turn-by-turn directions between locations. Live traffic is post-route ETA enrichment and does not change the returned path (path_influenced=false); truck traffic adjustments are slowdown-only. Supports car / truck / motorcycle / pedestrian / bicycle, with hazmat + dimension + toll avoidance for commercial routing. ETAs are returned as ISO 8601 with timezone offset (in the destination's local timezone). Use vehicle_profile presets (10 total — DRY_VAN_53, FLATBED_48/_40, STEP_DECK, TANKER, BOX_TRUCK_26, AUTO_CARRIER, SPRINTER_VAN, DOUBLE_TRAILER, OVERSIZE) when routing trucks — they set height/weight/length in one parameter.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesDestination: address string ('Houston, TX'), 'lat,lon' string, or { lat, lon } object
viaNoIntermediate stops in order; same shape as from/to. Up to 48 waypoints (max 50 total locations).
fromYesOrigin: address string ('Houston, TX'), 'lat,lon' string, or { lat, lon } object
unitsNoDistance units (default: miles). Accepts 'km'/'mi' as aliases.
hazmatNoSet true when transporting hazardous materials to avoid restricted routes
costingNoTransport mode (default: auto). Use 'truck' for commercial vehicles
axle_loadNoAxle weight in metric tons (e.g. 9.07t = 20,000 lbs per axle)
top_speedNoMaximum speed in km/h (default 105 for trucks)
use_ferryNoFerry preference 0-1 (0=avoid, 1=allow)
alternatesNoNumber of genuine motorized alternate routes to request (0, 1, or 2). Positive values require no via waypoints.
axle_countNoNumber of axles (default 5 for semi-trailer)
avoid_tollsNoAvoid toll roads when user requests toll-free routing
truck_widthNoTruck width in meters (e.g. 2.6m = 8'6")
truck_heightNoTruck height in meters (e.g. 4.11m = 13'6"). Triggers bridge avoidance
truck_lengthNoTruck length in meters (e.g. 16.2m = 53')
truck_weightNoTruck weight in metric tons (e.g. 36.3t = 80,000 lbs). Triggers weight-restricted road avoidance
use_highwaysNoHighway preference 0-1 (0=avoid, 1=prefer)
include_trafficNoApply post-route live-traffic ETA enrichment (default: true). Traffic does not change the returned path; truck adjustments are slowdown-only.
include_weatherNoAttach current conditions sampled along the route corridor (default: false). Post-route annotation only: weather does not change the returned path. Extra upstream lookup, opt-in only.
vehicle_profileNoPreset vehicle profile (10): DRY_VAN_53, FLATBED_48, FLATBED_40, STEP_DECK, TANKER, BOX_TRUCK_26, AUTO_CARRIER, SPRINTER_VAN, DOUBLE_TRAILER, OVERSIZE. Each sets height/weight/length/axle_count for that vehicle class in one parameter (e.g. DRY_VAN_53 = 4.11m tall, 36.3t, 22.25m long, 5 axles; OVERSIZE = 4.88m tall, 3.66m wide, 45.36t). The response echoes the applied dims in costing_options.truck. Any individual truck_height/truck_weight/etc. overrides a single field.
include_geometryNoRoute geometry shape control. "none" returns origin/destination Points only. "encoded" returns an encoded polyline6 string in a top-level `geometry` field plus origin/destination Points (≈95% smaller than raw GeoJSON; decode with @mapbox/polyline at precision 6). "full" emits decoded coordinates as a LineString in `geojson.features[0]`. When omitted (default), small routes use "full" and long routes auto-downgrade to "encoded" with a `geometry_truncated` warning.
include_elevationNoWhen true, include available route elevation fields. Point elevation may be returned for the origin and destination. Cumulative gain/loss is returned only when route-profile elevation is available.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
alternatesNo
display_hintNo
timezone_endNoIANA timezone at the route destination, or null when unresolved. Contains information from timezone-boundary-builder, which is made available under the Open Database License (ODbL) v1.0. Timezone boundaries © OpenStreetMap contributors. US legal-zone cross-check: U.S. Department of Transportation, Bureau of Transportation Statistics (public domain).
traffic_routeNo
timezone_startNoIANA timezone at the route origin, or null when unresolved. Contains information from timezone-boundary-builder, which is made available under the Open Database License (ODbL) v1.0. Timezone boundaries © OpenStreetMap contributors. US legal-zone cross-check: U.S. Department of Transportation, Bureau of Transportation Statistics (public domain).
costing_optionsNo
elevation_end_mNo
base_arrival_utcYesArrival time derived from the base duration, expressed as an ISO 8601 UTC timestamp.
elevation_end_ftNo
elevation_gain_mNo
elevation_loss_mNo
elevation_gain_ftNo
elevation_loss_ftNo
elevation_start_mNo
base_arrival_localYesArrival time derived from the base duration in the destination's local time, or null when the local timezone is unavailable.
elevation_start_ftNo
traffic_provenanceYes
timezone_end_statusNo
base_duration_secondsYesRoute duration before any traffic-based adjustment, in seconds.
effective_arrival_utcYesAuthoritative arrival time for this response, expressed as an ISO 8601 UTC timestamp.
timezone_start_statusNo
traffic_delay_secondsYesEffective duration minus base duration, in seconds. Positive means traffic made the ETA slower, negative means it made the ETA faster, and zero means the duration was unchanged. For truck costing, general traffic evidence is slowdown-only, so this value is never negative.
effective_arrival_localYesAuthoritative arrival time in the destination's local time, or null when the local timezone is unavailable.
timezone_artifact_versionNo
effective_duration_secondsYesAuthoritative duration for this response, in seconds, after any applicable traffic-based adjustment.

TDQS

A4.3/5.0
Behavior5/5

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

Beyond the readOnly/idempotent annotations, the description discloses key behaviors: traffic does not change the returned path, truck traffic adjustments are slowdown-only, ETAs use ISO 8601 with timezone offset in the destination's timezone, and vehicle_profile presets set dimensions in one parameter. No contradiction with 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?

Five sentences with no filler: purpose first, then high-value behavioral caveats, supported modes, ETA format, and truck-profile usage. The vehicle_profile list is long but earns its place as a quick reference, and the description stays well under the point of overwhelming the agent.

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

Completeness5/5

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

For a 22-parameter routing tool, the description captures the essential behavioral nuances (path-invariant traffic, slowdown-only truck traffic, ETA timezone, hazmat/dimension/toll support) while the input schema covers parameters and the output schema covers return shape. Nothing critical is missing for an agent to select and invoke the tool 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 the baseline applies: the schema already documents all 22 parameters and even gives vehicle_profile examples. The description reinforces vehicle_profile usage and adds the ETA timezone note, but that is primarily output semantics rather than new parameter-level meaning.

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 first sentence says 'Generate routes, ETAs, and turn-by-turn directions between locations' — a specific verb and resource with no tautology. It is clear about what the tool does, but it does not explicitly differentiate itself from sibling tools such as distance_matrix, so the differentiation is implicit rather than stated.

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 gives concrete when-to-use guidance: 'Use vehicle_profile presets (10 total ...) when routing trucks' and explains that traffic is a post-route ETA enrichment that does not alter the path. It does not spell out when not to use the tool or name alternative tools for many-to-many/matrix use cases.

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

distance_matrixA
Read-onlyIdempotent
Inspect

Compute road distances and travel times for every origin → destination pair. Endpoints accept free-text addresses or 'lat,lon' strings; N × M is capped at 625 pairs. Use for fleet dispatch, nearest-depot, and bulk ETA tables. Durations do NOT include live or historical traffic — see duration_basis; use directions for a traffic-adjusted ETA between two specific points.

ParametersJSON Schema
NameRequiredDescriptionDefault
unitsNoDistance units (default kilometers)
costingNoTransport mode (default auto)
originsYesOrigin endpoints (1–25): address or 'lat,lon'
destinationsYesDestination endpoints (1–25): address or 'lat,lon'

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
unitsYes
matrixYesmatrix[i][j] = origin i → destination j: { distance (in the requested units), time_seconds }; both null when no route exists
costingYes
originsYesGeocoded origin locations
destinationsYesGeocoded destination locations
duration_basisNoHow matrix durations were computed. `static_road_speeds` (the only value today): durations come from the road network's own speed data — posted limits and road-class defaults — never from historical or live traffic. Use `directions` for a traffic-adjusted ETA between two specific points.
upstream_errorNo
traffic_appliedNoWhether live or historical traffic influenced any matrix duration. Always false today — see `duration_basis`.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already signal read-only/idempotent, so the description adds non-obvious behavior: the 625-pair cap, endpoint format flexibility, and the crucial caveat that durations exclude live or historical traffic, pointing to duration_basis. No contradiction with 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?

Three compact sentences front-load the core capability, then add usage context and the key caveat. Every sentence earns its place with no filler.

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

Completeness5/5

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

For a four-parameter tool with full schema coverage and an output schema, the description covers selection, invocation constraints, and the main behavioral caveat. The reference to duration_basis is acceptable as a pointer to an output field.

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 all four parameters. The description adds the 625-pair cap and endpoint formats, but these are mostly derived from or redundant with the schema, so no extra parameter burden is needed.

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?

Clearly names a concrete operation (compute road distances and travel times) on a defined resource (every origin→destination pair). It also distinguishes itself from directions by noting it is for bulk pair matrices, not a single traffic-adjusted route.

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

Usage Guidelines5/5

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

Explicitly lists use cases (fleet dispatch, nearest-depot, bulk ETA tables) and names directions as the alternative when a traffic-adjusted point-to-point ETA is needed. This gives an agent a clear decision rule rather than a vague hint.

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

exploreA
Read-onlyIdempotent
Inspect

BROWSING / DISCOVERY search — administrative places (cities, neighbourhoods, boroughs, counties, regions) near a location. Use this when the user is exploring a REGION rather than looking for a specific category. Supports population filtering ('cities > 100k'), ranking by significance or distance, and layer filtering (locality / neighbourhood / borough / county / region). Venues, addresses and streets are NOT served here — for venues and POI categories (gas, food, charging, etc.) use search_places instead. Each result carries its distance in the caller's units and a bearing from the center.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNoLatitude of center point
lonNoLongitude of center point
sizeNoMax results (default 10, max 50)
sortNoRanking basis. Default `population` — significance (population where the source has it) with distance as the tiebreak. `distance` is nearest first; `combined` blends population against a distance decay. The basis applied is echoed in meta.ranking.
unitsNoUnits for a bare numeric `radius`: miles (default) or kilometers. Accepts the aliases mi, mile, imperial (miles) and km, kilometer, kilometre, kilometres, metric (kilometers), any case; echoed as miles|kilometers. Ignored when `radius` already carries a unit suffix; a contradicting pair is rejected. Does not supply a radius on its own (the default is per layer — 150 km for locality/county/region, 25 km for neighbourhood/borough; tightest wins when mixed) but selects the display unit of the meta.radius / meta.units echo.
layersNoComma-separated administrative layers: locality (default), neighbourhood, borough, county, region. venue, address, street and unknown names are rejected with a structured invalid_layer error — use search_places for venues. Radius policy is per layer: locality/county/region default 150 km and cap at 500 km; neighbourhood/borough default 25 km and cap at 100 km; a mixed request takes the tightest default and cap. With several layers, `size` is split evenly between them (remainder to the first) so one dense layer cannot flood the result.
radiusNoSearch radius — e.g. radius: 30, units: 'miles'. Bare numbers are miles unless units is set; kilometers via units or a km suffix ('50km'); aliases mi/km/imperial/metric. A value carrying its own unit suffix ('50km', '30mi') is also accepted for compatibility and its suffix wins. Per-layer policy: locality/county/region default 150 km (93.206 mi) and cap at 500 km (~310 mi); neighbourhood/borough default 25 km (15.534 mi) and cap at 100 km (~62 mi); a request naming several layers takes the tightest default and cap among them. Numeric values above 500 fail input validation before the tool runs; a string form over the maximum ('600km') or an in-range number that is over the cap once read as miles (e.g. 400, or 400 with units 'miles' — 644 km) returns a structured radius_exceeds_max error naming the governing cap instead of results.
locationNoCenter point address or 'lat,lon'
min_populationNoMinimum population filter, applied JS-side to whichever layers are served (locality, neighbourhood, borough, county, region).
boundary_countryNoISO country code to restrict results (alpha-2 or alpha-3)

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
display_hintNo

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the annotations (readOnly, idempotent), the description reveals behavioral nuances: per-layer default radii and caps, how `size` is split across layers, the `meta.ranking` echo, and structured error responses like `radius_exceeds_max`. It also explains that `units` does not supply a radius on its own. This exceeds the annotation baseline.

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 dense but logically organized, front-loading the core purpose and usage. Every sentence carries information, though some redundancy exists (e.g., repeated mentions of 'radius policy is per layer' and unit aliases in multiple parameters). Slightly verbose but not wasteful.

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

Completeness5/5

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

For a tool with 10 parameters and complex interdependencies, the description covers all critical interactions: how radius and units combine, layer-specific caps, error cases, and tie-breaking behavior. Since an output schema is present, lack of return details is acceptable. The agent has enough context to invoke it correctly in any scenario.

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

Parameters5/5

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

The schema already covers 100% of parameters, but the description adds substantial meaning: `units` aliases and precedence rules, `layers` per-layer radius policies, `radius` error conditions and unit-suffix handling, and `sort` ranking semantics. This transforms bare schemas into actionable knowledge, well above the baseline of 3.

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?

The description clearly states the tool is for browsing/discovery of administrative places near a location, and immediately distinguishes it from `search_places` for venues. The verb 'explore' and resource 'administrative places' are explicit, making the purpose unmistakable.

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

Usage Guidelines5/5

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

It explicitly tells the agent when to use this tool ('when the user is exploring a REGION') and when not to use it ('venues, addresses and streets are NOT served here... use search_places'), plus provides detailed guidance on radius policies, layer restrictions, and unit handling. This leaves no ambiguity about selection.

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

geocodeA
Read-onlyIdempotent
Inspect

Convert an address, place name, street, or intersection into coordinates and structured location results. Use when input is text and you need coordinates before routing, weather, or search. Supports street-level resolution and proximity biasing.

ParametersJSON Schema
NameRequiredDescriptionDefault
sizeNoNumber of candidates to return (default 5, max 40)
queryYesAddress, place name, street, intersection (e.g. 'Broadway and 42nd Street New York'), or free-form location text
layersNoRestrict to: address, street, venue, locality. Use layers=street when user clearly wants a street entity. Use layers=venue for stadiums, monuments, parks, and named POIs (e.g. 'Minute Maid Park', 'Lambeau Field', 'Statue of Liberty') — bypasses address-parser tokenization that otherwise resolves venue+state to the state region centroid
focus_latNoBias results near this latitude — use when user says 'near me' or 'close to'
focus_lonNoBias results near this longitude
boundary_countryNoISO country code to reduce ambiguity (alpha-2 or alpha-3)

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
precisionNo
display_hintNo

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the safety profile is covered. The description adds behavioral capability context ('street-level resolution and proximity biasing'), which is useful, but says nothing about result ordering, fallback behavior when no match, or accuracy/rate 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?

Three sentences, front-loaded with the core operation before usage and capabilities. Compact and no filler, though the capability sentence is somewhat redundant with the schema's parameter descriptions.

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?

An output schema exists, so return values need not be explained. The description covers what the tool does, when to use it, and its resolution capability, which is enough for a geocoding call. The main gap is lack of sibling differentiation in a crowded geocoding family.

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 six parameters are already richly documented in the schema (including the detailed layers guidance and focus_lat/lon biasing). The description only gestures at 'proximity biasing,' which the schema already explains, so it adds little beyond the structured fields. 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 ('Convert') and resource ('address, place name, street, or intersection into coordinates'). This implicitly distinguishes it from reverse_geocode (the inverse operation), though it never names siblings like geocode_structured or batch_geocode for explicit differentiation.

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?

Provides usage context ('Use when input is text and you need coordinates before routing, weather, or search'), which implies when the tool is needed. However, it does not distinguish this tool from near-siblings such as geocode_structured, batch_geocode, or resolve_intersection, leaving the agent to infer which one to pick.

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

geocode_structuredA
Read-onlyIdempotent
Inspect

Geocode from discrete address components (address, locality, region, postalcode, country) instead of one free-text string. Use when the input is already fielded (forms, CRM records, stop tables) — skips free-text parsing so components can't be mis-tokenized. At least one component is required. No cross-street field: for named intersections use resolve_intersection or geocode.

ParametersJSON Schema
NameRequiredDescriptionDefault
sizeNoNumber of candidates to return (default 5, max 40)
regionNoState / province — full name or abbreviation (e.g. 'TX')
addressNoStreet address — house number + street name (e.g. '1600 Pennsylvania Ave NW')
countryNoISO 3166-1 alpha-2/alpha-3 country code (full names also resolve)
localityNoCity / town name
focus_latNoBias results near this latitude
focus_lonNoBias results near this longitude
postalcodeNoPostal / ZIP code
boundary_countryNoScope results to this ISO country code — wins over `country` for boundary filtering

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
precisionNo
display_hintNo

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnly, openWorld and idempotent, so safety is covered. The description adds non-obvious behavioral facts: that free-text parsing is skipped (so components can't be mis-tokenized), that at least one component is required despite required=0 in the schema, and that there is no cross-street field. It stops short of describing the candidate set or ordering, but the added context is substantial.

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?

Three tight sentences: the differentiator is front-loaded, the usage trigger comes second, and the exclusion/alternative routing comes last. No filler and nothing repeated from the schema or annotations.

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?

An output schema exists, so return values need not be explained. Given a 9-parameter, fully documented schema plus safety annotations, the description supplies exactly the extra context an agent needs — the input-shape constraint, the minimum-component requirement, and the missing cross-street capability.

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 every parameter including size, focus_lat/lon and boundary_country is already documented in the schema; the baseline is 3. The description enumerates the component fields but adds no syntax or precedence guidance beyond the schema (e.g. boundary_country winning over country is left to the schema text).

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 (Geocode) and the distinctive resource/input mode (discrete address components vs. one free-text string), and immediately distinguishes itself from geocode and resolve_intersection. An agent can tell this apart from its siblings without opening a schema.

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

Usage Guidelines5/5

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

Explicitly says when to use it ('input is already fielded (forms, CRM records, stop tables)') and names the alternatives for the excluded case ('for named intersections use resolve_intersection or geocode'). Both routing conditions are stated, not inferred.

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

geofence_containsA
Read-onlyIdempotent
Inspect

Tests one or more points for containment inside a polygon you supply as GeoJSON (Polygon, MultiPolygon, or a Feature/FeatureCollection wrapping one). Pure geometry against your own shape - it does not search a place index, so use explore or search_places to find what's near a point instead. Boundary points count as contained. Up to 1000 points per call, against a polygon of up to 100 rings/parts and 1000 positions per ring; larger inputs are rejected. Runs locally with no external lookup, but still counts as one metered request like other tools, so batch points into a single call rather than looping. Errors, rather than returning false, when the polygon is structurally invalid. Returns one boolean per point, in order, plus contained_count and point_count.

ParametersJSON Schema
NameRequiredDescriptionDefault
pointsYesPoints to test ({ lat, lon } each), up to 1000
polygonNoA GeoJSON Polygon / MultiPolygon geometry, a Feature wrapping one, or a FeatureCollection

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsYesOne containment boolean per input point (in order)
warningsNo
point_countYesNumber of points tested
contained_countYesHow many input points are contained

TDQS

A4.7/5.0
Behavior5/5

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

The description discloses several behaviors beyond the annotations: boundary points count as contained, structurally invalid polygons cause errors rather than false returns, and it runs locally with no external lookup yet still counts as a metered request. It also clarifies that it returns one boolean per point plus counts. No contradictions with readOnlyHint, openWorldHint, or idempotentHint.

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 well-structured, front-loading the core purpose and then systematically covering limits, behavior, error handling, and alternatives. Each sentence adds distinct value without redundancy, and the length is justified by the richness of behavioral details needed for correct usage.

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?

Given that an output schema exists (though not shown here) and annotations cover safety and idempotency, the description addresses all critical aspects: inputs, limits, error behavior, batching, local execution, and alternative tools. Nothing an agent needs to invoke this tool correctly 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?

The input schema already fully describes both parameters with constraints (maxItems for points, GeoJSON types for polygon). The description adds context about limits and batching but does not introduce new parameter-specific semantics beyond what the schema provides. With 100% schema description coverage, a baseline of 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?

The description states a specific verb ('tests') and resource ('points for containment inside a polygon you supply as GeoJSON'), and explicitly distinguishes itself from sibling tools by noting it does not search a place index and directing users to explore or search_places for proximity queries. This makes the tool's purpose unmistakable and differentiates it from similar tools.

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

Usage Guidelines5/5

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

It explicitly states when to use the tool (testing containment against a user-supplied polygon) and when not to (finding places near a point), naming the alternative tools. It also provides operational guidance on batching points into a single call to avoid repeated metered requests, which is actionable and prevents misuse.

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

isochroneA
Read-onlyIdempotent
Inspect

Computes reachability polygons: the area reachable from an origin within given travel-time or travel-distance bands. Use for service coverage, dispatch range, territory design, and 'how far can I get in X minutes' questions; use directions or distance_matrix for a route or distance between specific points instead. Pass multiple bands in one call (contours_minutes:[10,20,30]) for nested polygons in one response, up to 4 bands, defaulting to 15/30/60-minute driving bands if none given. location accepts an address string or 'lat,lon'. costing selects the travel profile (auto default, or truck/bicycle/pedestrian/motorcycle). Read-only and cached. Returns a GeoJSON FeatureCollection of nested polygon contours, one per band.

ParametersJSON Schema
NameRequiredDescriptionDefault
costingNoTransport mode
locationYesCenter point address or 'lat,lon'
contours_kmNoDistance bands in km. Max 4 bands per call (over returns 400).
truck_heightNoTruck height in meters
truck_weightNoTruck weight in metric tons
contours_minutesNoTime bands in minutes, e.g. [10, 20, 30]. Max 4 bands per call (over returns 400).

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
display_hintNo

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint. The description adds 'Read-only and cached' (caching is not in annotations) and details the default band behavior (15/30/60-minute driving) and output format (GeoJSON FeatureCollection of nested polygon contours). This goes well beyond the structured metadata, providing rich behavioral context without contradicting any annotation.

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 efficiently structured: it opens with the core function, then use cases, then usage specifics, and finally output format. Every sentence contributes essential information with no filler. The length is justified by the tool's complexity, and the key points are front-loaded.

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?

The description is complete for an agent to call the tool correctly. It covers the purpose, usage context, parameter behavior, defaults, and output format. With an output schema present, the description need not detail return structures beyond the high-level summary it provides. Nothing critical is missing for correct invocation.

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

Parameters4/5

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

Schema description coverage is 100%, so the baseline is 3. The description adds meaningful usage context beyond the schema: it explains that location accepts an address or 'lat,lon' (schema already says this, but the description reinforces it), and it clarifies how to pass multiple bands with an example and the default. It also highlights that costing selects the travel profile with the default auto. These additions slightly elevate the value beyond the schema, so a 4 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?

The description opens with a precise definition: 'Computes reachability polygons: the area reachable from an origin within given travel-time or travel-distance bands.' It immediately distinguishes itself from sibling tools by explicitly naming directions and distance_matrix for point-to-point routes. This is a specific verb+resource that leaves no ambiguity.

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

Usage Guidelines5/5

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

Usage guidance is explicit: it lists concrete use cases (service coverage, dispatch range, territory design) and tells the agent to use directions or distance_matrix instead for routes between specific points. It also explains how to pass multiple bands (contours_minutes:[10,20,30]) and the default bands, giving clear when-to-use and how-to-use instructions.

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

issue_api_key
Read-onlyIdempotent
Inspect

Get the link to create a ThinAir GEO (geocoding/routing) API key. Returns console_url (the signed-in ThinAir Geo console) and instructions; it does NOT return a key and does not create, rotate or revoke any key. The owner signs in, creates the key there and sees it once in their own browser, then sends it as an Authorization: Bearer header. Existing keys keep working. Counts as 1 query against your daily quota. NOTE: keys created there work ONLY against ThinAir Geo — they do NOT authenticate against ThinAir Data, which issues its own ta_data_* keys from its own identically-named tool.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
planNo
errorNo
statusYes
console_urlNoLink to the signed-in ThinAir Geo console, where the owner creates an API key and sees it once in their own browser. This tool never returns a key.
instructionsNoHow to create the key in the console and send it (Authorization: Bearer). Surface to the user as written.
locateA
Read-onlyIdempotent
Inspect

Snap one coordinate to the road network and return the matched road's context: name, road class, speed limit, bearing, snap distance, side of street, truck legality, and toll/ferry/highway/bridge/tunnel flags — plus the IANA timezone. Use to answer 'what road is this point on and what are its rules?' for fleet/telematics snapping, geofence edge checks, or enriching a GPS fix. Set include_elevation for terrain-sourced point elevation_m; grade_pct is a forward-compatible field that stays null for now. Read road_status, not matched alone: matched — a road was found and road is filled; no_road_nearby — a real answer: no routable road is near the point for this travel profile; unavailable — the road lookup could not be answered right now, so matched:false / road:null say nothing about the point, retryable is true, and the timezone and any requested elevation are still looked up separately (see timezone_status and warnings). Never a guess.

ParametersJSON Schema
NameRequiredDescriptionDefault
latYesLatitude
lonYesLongitude
unitsNoUnit system for the human summary — auto-detected (US/UK → imperial) when omitted.
costingNoTravel profile scoping edge access/legality. Default 'auto'.
include_elevationNoOpt-in to point elevation — populates elevation_m/elevation_ft from terrain data (null with an 'elevation_unavailable' warning only where terrain isn't covered). grade_pct is a forward-compatible field that stays null for now (reserved for an elevation-enhanced road network).

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
roadNo
itemsNo
geojsonNo
matchedNo
metricsNo
summaryNo
locationNo
timezoneNoIANA timezone for the point, or null unless timezone_status is resolved. Contains information from timezone-boundary-builder, which is made available under the Open Database License (ODbL) v1.0. Timezone boundaries © OpenStreetMap contributors. US legal-zone cross-check: U.S. Department of Transportation, Bureau of Transportation Statistics (public domain).
warningsNo
grade_pctNo
retryableNoPresent and true only when `road_status` is `unavailable`: the same call may succeed shortly.
elevation_mNo
road_statusNoWhy `road` is what it is. `matched`: a routable road was found. `no_road_nearby`: the lookup answered and found no routable road near the point for this travel profile. `unavailable`: the road lookup could not be answered right now; this says nothing about the point, `retryable` is true, and the timezone and any requested elevation are still looked up separately.
display_hintNo
elevation_ftNo
timezone_statusNo
timezone_artifact_versionNo

TDQS

A4.4/5.0
Behavior5/5

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

Annotations already cover read-only/idempotent/open-world, yet the description adds substantial behavior: the three-valued road_status contract, the warning that 'unavailable' makes matched:false meaningless about the point, that retryable is set, and that timezone/elevation are still looked up independently. This is exactly the beyond-annotations context the bar is meant to reward.

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?

Front-loaded with the action, then usage, then a well-structured status-contract paragraph. It is long and mildly redundant, restating the elevation/grade_pct caveat that the schema already carries, but nearly every sentence earns its place.

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 an output schema present, the description need not enumerate return values, yet it fully explains the road_status state machine, the nullability caveats, and retry semantics — the precise gaps an agent would otherwise misread. Nothing needed to call it correctly 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%, so lat/lon/units/costing/include_elevation are already documented; baseline 3 applies. The description re-explains include_elevation and the forward-compatible grade_pct but adds no new syntax or constraints (units auto-detection and costing profiles live only in 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?

Opens with a specific verb+resource: 'Snap one coordinate to the road network and return the matched road's context.' Enumerates the returned fields (name, road class, speed limit, bearing, side of street, truck legality, flags, timezone), which separates it cleanly from siblings like map_match, reverse_geocode, and trace_attributes.

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?

Gives explicit use contexts — fleet/telematics snapping, geofence edge checks, enriching a GPS fix — and frames the question it answers. However, it never names an alternative sibling (e.g., reverse_geocode or map_match) or states when-not to use it, so routing between near-neighbors 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.

map_matchA
Read-onlyIdempotent
Inspect

Map matching snaps raw GPS breadcrumbs to the road network. Feed a recorded trace (2–100 points) and get back the road-accurate route that was actually driven: matched geometry, distance, time, road names, and a 0–1 match confidence. matched: true only means a route was returned — gate on match_status: full when every input point was matched or interpolated onto the road network and the match is one continuous section, none when no point was, otherwise partial. coverage gives the per-point counts, unmatched_ranges (0-based input indexes that did not match) and route_sections (above 1, the geometry, distance and time cover only the first section — split the trace there). match_status is null, with coverage.unavailable_reason, when the per-point check could not be completed. Sparsely-reported traces (consecutive fixes farther apart than the default breakage distance — e.g. fleet units reporting every several minutes on a highway) can split into multiple sections; increase breakage_distance_m to keep them as one. Total matched distance is limited to 200 km per call — split longer sparse traces by distance, not only by the 100-point cap. Use for fleet trace cleanup, mileage from GPS logs, and reconstructing routes from telemetry. road_names come from the route's maneuver points, so they cover the roads the route turns onto or starts on — for the name of every segment actually travelled, use trace_attributes. For planning a route between places, use directions instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
shapeYesRaw GPS breadcrumb trail in travel order — 2 to 100 points of { lat, lon, time? }. `time` is optional epoch seconds; timestamps improve match quality on noisy traces.
costingNoTransport mode the trace was recorded with (default: auto)
search_radiusNoSnap radius in meters around each point (1–100). Increase for noisy GPS.
vehicle_profileNoTruck preset (DRY_VAN_53, FLATBED_48, BOX_TRUCK_26, …) — same 10-profile table as directions. Implies costing=truck.
breakage_distance_mNoMaximum gap, in meters, between consecutive fixes before the trace is split into separate sections (100–20000). Increase for sparsely-reported GPS, such as fleet units reporting every several minutes on a highway. Optional — omitted uses the default.

Output Schema

ParametersJSON Schema
NameRequiredDescription
legsYes
metaNo
costingYes
geojsonNo
matchedYesTrue when a route was returned for the trace. It does NOT mean the whole trace matched — use `match_status`.
coverageNoPer-point coverage of the trace from the matcher's own per-point status — independent of the distance-based `confidence`. Every key is always present.
geometryNo
confidenceYes0–1: fraction of input GPS points within the snap tolerance of the matched route. A distance heuristic: it ignores point order and which parallel roadway was matched. For the matcher's own per-point result use `match_status` / `coverage`.
road_namesYes
distance_kmYes
match_statusNoWhole-trace match status from the matcher's own per-point results. `full`: every input point was matched or interpolated onto the road network AND the match is one continuous section. `none`: no input point was matched or interpolated. `partial`: anything else — some points unmatched, or the match broke into more than one section. null when the per-point check could not be completed; `coverage.unavailable_reason` says why. Gate on this field, not on `matched`.
costing_optionsNo
vehicle_profileNo
duration_secondsYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations declare readOnlyHint=true and idempotentHint=true, and the description does not contradict them — map matching is a pure read operation. Beyond the annotations, the description discloses substantial behavior: the matched:true vs match_status distinction (full/none/partial), coverage counts, unmatched_ranges, route_sections semantics (above 1, only first section's geometry/distance/time returned), the 200 km matched-distance cap, sparse-trace splitting behavior, and the caveat that road_names derive only from maneuver points. This is rich context well beyond the structured fields.

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 long and information-dense, but every sentence carries real behavioral or routing content — return semantics, edge cases, limits, alternatives. It is front-loaded with the core purpose and output before diving into nuance. Given the subtlety of match_status and route_sections, the length is earned; it's thorough rather than bloated.

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

Completeness5/5

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

For a high-complexity tool with subtle return semantics, the description covers purpose, all critical edge cases (sparse traces, 200 km limit, per-point matching failure via unavailable_reason), return-value interpretation, and sibling routing. An output schema exists for structured returns, and the description still clarifies the ambiguous parts (what matched:true really means, what route_sections>1 implies). Nothing an agent needs to call it correctly is missing.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description adds value on top: it explains the behavioral consequence of breakage_distance_m (sparse traces split into sections; increase to keep them one), ties the 200 km limit to distance-based splitting of long traces, and clarifies costing/vehicle_profile interplay via the truck preset note. It doesn't deeply re-explain every param since the schema already does, but the added behavioral context pushes it above baseline.

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?

The description states a specific verb and resource ('snaps raw GPS breadcrumbs to the road network') and enumerates the output (matched geometry, distance, time, road names, match confidence). It explicitly distinguishes itself from siblings — 'For planning a route between places, use directions instead' and 'use trace_attributes' for per-segment names — so an agent can select it correctly without opening other schemas.

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

Usage Guidelines5/5

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

Provides explicit use cases ('Use for fleet trace cleanup, mileage from GPS logs, and reconstructing routes from telemetry') plus clear exclusions with named alternatives ('For planning a route between places, use directions instead'; 'for the name of every segment actually travelled, use trace_attributes'). This is exactly the when/when-not guidance the rubric rewards.

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

place_getA
Read-onlyIdempotent
Inspect

Look up a place by its stable ThinAir id (ta_place_… / ta_intersection_…) as returned in the id field of geocode, reverse_geocode, search_places, or resolve_intersection results. Ids are deterministic and survive re-serves — safe to store as favorites or foreign keys. Returns the canonical name, label, layer, and coordinates. Unknown or expired ids error with re-search guidance.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThinAir place id exactly as returned in a previous response's `id` field — ta_place_<key> or ta_intersection_<key>

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
latYes
lonYes
metaNo
nameNo
typeYes
labelNo
layerNo
componentsNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare readOnlyHint and idempotentHint, lowering the burden. The description adds meaningful behavior: ids survive re-serves (idempotency), return value contents, and error handling for unknown/expired ids with re-search guidance. This goes well beyond the annotations and gives the agent a clear model of what happens.

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 three sentences, each contributing unique information: purpose, id source/stability, and return/error behavior. It is front-loaded with the core action and avoids redundancy with the schema.

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

Completeness5/5

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

For a simple single-parameter lookup tool with an output schema and rich annotations, the description is complete. It covers purpose, id provenance, stability, return content, and error behavior. No significant gaps remain.

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?

The schema already provides full parameter coverage (100%) including the id format and constraints. The description adds value by naming the exact source tools (geocode, reverse_geocode, search_places, resolve_intersection) and highlighting id stability and determinism, which are not in the schema. This enriches the semantics 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?

The description uses a clear verb ('Look up') with a specific resource ('place by its stable ThinAir id') and identifies the id format (ta_place_… / ta_intersection_…). It also names the sibling tools that produce these ids, which distinguishes this lookup tool from geocoding and search tools.

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?

The description provides clear context for when to use this tool: when you have an id from geocode, reverse_geocode, search_places, or resolve_intersection, and want canonical data. It emphasizes the ids are deterministic and safe to store, implying reuse over repeated lookups. It doesn't explicitly state when not to use alternatives, but the context is strong enough.

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

quotaA
Read-only
Inspect

Check current usage, remaining limits, plan, and quota breakdown for the caller. FREE TO CALL — never counts against your quota, never blocked by it. Use this proactively when the user asks about usage or seems near limits.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
mcpYes
upstreamNo

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the readOnlyHint annotation, the description reveals a critical behavioral trait: the call never counts against quota and is never blocked by it. This is valuable context not present in annotations and directly influences the agent's willingness to call the tool.

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 two sentences, front-loaded with the core purpose, then a high-value clarifying detail about quota impact. Every word earns its place with no redundancy.

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

Completeness5/5

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

For a simple, parameterless tool, the description fully covers what it returns (usage, limits, plan, breakdown) and when to call it. The output schema exists to detail return structure, so the description is complete.

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?

The tool has zero parameters, so no parameter descriptions are needed. The schema already fully covers this aspect (100% coverage with no properties), meeting the baseline for no-parameter tools.

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?

The description clearly states the tool's function: 'Check current usage, remaining limits, plan, and quota breakdown for the caller.' It uses a specific verb ('Check') and precise resource identifiers, distinguishing it from sibling tools like issue_api_key or geocoding services.

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

Usage Guidelines5/5

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

Provides explicit when-to-use guidance: 'Use this proactively when the user asks about usage or seems near limits.' Also adds that it is 'FREE TO CALL — never counts against your quota, never blocked by it,' reinforcing why it should be used without hesitation.

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

resolve_intersectionA
Read-onlyIdempotent
Inspect

Resolve a NAMED cross-street (street1 × street2 within a locality/region/country) to a single best coordinate with a confidence score and a fleet-safe fallback. High-confidence tier matches US-metro highway corners; named non-highway streets resolve via the geocoder fallback. For free-form streets use geocode.

ParametersJSON Schema
NameRequiredDescriptionDefault
regionNoState / province (full name or abbreviation, e.g. 'TX')
countryNoISO 3166-1 alpha-2/alpha-3 country code
street1YesFirst street of the cross-street pair
street2YesSecond (cross) street of the pair
localityNoCity / town that scopes the lookup

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
adminNo
featureYesBest resolved intersection feature, including validated optional intersection provenance, or null when nothing resolved
warningsNo
precisionNo
confidenceYesResolved confidence 0–1 (0 when nothing resolved)
fallback_usedNoTrue when the geocoder fallback produced the answer
upstream_errorNo

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnly/openWorld/idempotent, so the safety profile is covered. The description adds genuine behavioral context beyond that: a confidence score is returned, a fleet-safe fallback exists, and resolution is tiered (high-confidence highway corners vs geocoder fallback). It does not discuss failure modes or rate 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?

Three sentences, front-loaded with the core action and scope, followed by tier behavior and the routing hint. Dense but each sentence carries distinct information with no filler.

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 an output schema present, return value shape need not be described, and annotations cover the safety profile. The description supplies the tiering and fallback context an agent needs to interpret results; only sibling disambiguation against geocode_structured 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%, so all five parameters (street1, street2, locality, region, country) are already documented in the schema. The description restates the street1 × street2 pairing and the locality/region/country scoping but adds no format or constraint detail beyond it; baseline 3 applies.

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 (Resolve) and resource (a NAMED cross-street, defined as street1 × street2 scoped by locality/region/country), and explicitly names the sibling it is not (geocode for free-form streets). An agent can distinguish this from geocode/geocode_structured 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 Guidelines4/5

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

Gives a clear routing rule: use this for NAMED cross-streets, use geocode for free-form streets. It also explains that high-confidence tier matches US-metro highway corners while named non-highway streets fall back to the geocoder. It does not disambiguate against geocode_structured, so it stops short of 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.

reverse_geocodeA
Read-onlyIdempotent
Inspect

Converts a coordinate pair into the nearest addresses, streets, venues, or administrative places, ordered by proximity. Use when starting from GPS or a map position; for text-to-coordinates use geocode, and for a point's road-network context (name, class, speed limit, legality) use locate instead. Read-only and cached. Near the poles (|lat| >= 85 degrees) the index is too sparse for a real nearest match, so this returns no results rather than a distant wrong guess. Returns up to size candidates (default 5, max 40); layers restricts the type returned (address, street, venue, neighbourhood, locality, county, region, country, postalcode, and more). Each result carries a confidence score, layer, label, and coordinates, same shape as geocode.

ParametersJSON Schema
NameRequiredDescriptionDefault
latYesLatitude
lonYesLongitude
sizeNoNumber of nearby candidates (default 5, max 40)
layersNoRestrict to a comma list of: address, street, venue, neighbourhood, borough, locality, localadmin, county, macrocounty, region, macroregion, dependency, country, continent, postalcode, coarse. Admin layers resolve from the nearest indexed feature's parent hierarchy.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
precisionNo
display_hintNo

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already cover read-only, open-world, and idempotent behavior, but the description adds caching and the important pole edge case where it returns no results rather than a distant wrong guess. It also explains that results are bounded by size and carry confidence scores, labels, and coordinates.

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 front-loaded with purpose, then routing alternatives, then behavioral caveats, so the most important information comes first. It is information-dense and earns most of its length, though 'Read-only and cached' partly repeats annotations and the layers enumeration is somewhat verbose.

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?

Given the tool's complexity, the description covers purpose, alternatives, edge cases, return cardinality, and layer semantics, while the output schema handles result shape. With rich annotations and full schema coverage, an agent has everything needed to 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 the input schema already documents lat/lon bounds, size default/max, and the layers list in more detail. The description repeats the size default/max and gives layer examples, but adds no new syntax or semantic detail beyond the schema. Baseline 3 applies.

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: converts a coordinate pair into nearest addresses, streets, venues, or administrative places, ordered by proximity. This clearly distinguishes the tool from siblings like geocode and locate, so an agent can identify it without opening the schema.

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

Usage Guidelines5/5

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

Explicitly says to use it when starting from GPS or a map position, and names the alternatives: geocode for text-to-coordinates and locate for road-network context. The when/when-not routing is unambiguous.

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

search_placesA
Read-onlyIdempotent
Inspect

CATEGORY-specific POI search near a point — gas stations, truck stops, restaurants, charging stations, etc. Use this when the user has a specific TYPE of place in mind (food / health / retail / fuel / accommodation / nightlife / transport / government / recreation). For broader DISCOVERY (e.g. 'cities within 50 miles' or 'venues by population'), use explore instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNoCenter latitude (alternative to `center` object)
lonNoCenter longitude (alternative to `center` object)
limitNoMax results (default 10, max 50)
queryNoFree-text place query such as 'truck stop', 'restaurant', 'charging station'. One of `query` or `categories` is required — a bare center (`lat`+`lon`/`center`) with neither is rejected.
unitsNoUnits for a bare numeric `radius`: miles (default) or kilometers. Accepts the aliases mi, mile, imperial (miles) and km, kilometer, kilometre, kilometres, metric (kilometers), any case; echoed as miles|kilometers. Ignored when `radius` already carries a unit suffix; a contradicting pair is rejected. Not valid with `radius_m` alone — radius_m is always meters, so that pair is rejected. Does not supply a radius on its own (the default 50 km applies) but selects the display unit of the `units` echo.
centerNoCenter point for nearby search ({lat, lon} object or JSON string). You can also pass flat lat/lon.
layersNoRestrict to: venue, address
radiusNoSearch radius — e.g. radius: 30, units: 'miles'. Bare numbers are miles unless units is set; kilometers via units or a km suffix ('5km'); aliases mi/km/imperial/metric. A value carrying its own unit suffix ('30mi', '5km') is also accepted and its suffix wins. Default 50 km (about 31 mi); maximum 50 km (up to 31.068 mi). Preferred over `radius_m`. Numeric values above 50 fail input validation before the tool runs; a string form over the maximum ('60km') or an in-range number that is over the cap once read as miles (e.g. 40, or 40 with units 'miles' — 64 km) is rejected with a radius error instead of results.
radius_mNoSearch radius in meters (max 50000 — i.e. 50 km / ~31 mi; default 50 km; 0 means 'not supplied' and applies the default). Accepted alias; `radius` + `units` is preferred. Sending both is only valid when they agree. Do not pair with `units`.
categoriesNoStructured categories: food, fuel, charging_station, education, health, entertainment, retail, accommodation, nightlife, transport, government, recreation. One of `categories` or `query` is required — a bare center (`lat`+`lon`/`center`) with neither is rejected.

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
display_hintNo

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint, covering safety and idempotency. The description adds the behavioral nuance that this is a category-filtered, point-anchored search, which clarifies its scope beyond the annotations. It doesn't cover return details, but the output schema exists, so the bar is lower.

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: the first states the tool's purpose with concrete examples, the second gives usage guidance and names the alternative. No filler, and the key category-specific behavior is front-loaded.

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

Completeness5/5

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

For a tool with 10 parameters, nested objects, and a full output schema, the description provides the essential decision context (when to use vs `explore`) without duplicating schema details. Everything an agent needs to decide on and invoke it correctly is present.

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 10 parameters are fully documented in the schema. The description reinforces the importance of the categories parameter by listing examples, but does not add substantive semantics beyond what the schema already provides. Baseline of 3 applies.

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?

The description clearly states the tool performs a CATEGORY-specific POI search near a point, with explicit examples and a list of categories. It also distinguishes itself from the sibling `explore` by naming the specific use case (specific type vs broader discovery), making its purpose unambiguous.

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

Usage Guidelines5/5

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

Explicitly tells when to use this tool ('when the user has a specific TYPE of place in mind') and when not to, pointing directly to `explore` as the alternative for broader discovery. This is the ideal level of routing guidance.

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

trace_attributesA
Read-onlyIdempotent
Inspect

Trace attributes return road/network attributes for matched traces. Feed a GPS breadcrumb trail (2–100 points) and get per-segment road names, road classes, speed limits, surfaces, truck-route flags, and segment lengths along the matched route, plus a matcher confidence score. Sparsely-reported traces (consecutive fixes farther apart than the default breakage distance — e.g. fleet units reporting every several minutes on a highway) can split into multiple sections; increase breakage_distance_m to keep them as one. Total matched distance is limited to 200 km per call — split longer sparse traces by distance, not only by the 100-point cap. Use to audit what roads a vehicle actually used (speed-limit compliance, truck-route adherence, surface checks). For just the matched route line, use map_match.

ParametersJSON Schema
NameRequiredDescriptionDefault
shapeYesRaw GPS breadcrumb trail in travel order — 2 to 100 points of { lat, lon, time? }. `time` is optional epoch seconds; timestamps improve match quality on noisy traces.
costingNoTransport mode the trace was recorded with (default: auto)
search_radiusNoSnap radius in meters around each point (1–100). Increase for noisy GPS.
vehicle_profileNoTruck preset (DRY_VAN_53, FLATBED_48, BOX_TRUCK_26, …) — same 10-profile table as directions. Implies costing=truck.
breakage_distance_mNoMaximum gap, in meters, between consecutive fixes before the trace is split into separate sections (100–20000). Increase for sparsely-reported GPS, such as fleet units reporting every several minutes on a highway. Optional — omitted uses the default.

Output Schema

ParametersJSON Schema
NameRequiredDescription
metaNo
edgesYes
adminsNo
costingYes
geojsonNo
matchedYes
geometryNo
confidenceYesMatcher confidence 0–1
edge_countYes
road_namesYes
distance_kmYes
costing_optionsNo
vehicle_profileNo
duration_secondsNo

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the safety profile is covered. The description adds valuable behavioral context: sparse traces can split into multiple sections, and total matched distance is capped at 200 km. This goes beyond the structured hints, though it stops short of describing output schema details (which are separately provided).

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 compact yet dense: three sentences carry purpose, edge-case handling, and alternatives. The key purpose is front-loaded, and the usage note is placed at the end. It earns its length, though the split/limit guidance could be tightened slightly.

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?

Given the output schema exists (and the description enumerates returned attributes), the description covers all operational needs: input range (2–100 points), spatial limits, splitting behavior, and use-case fit. It leaves no critical gap for an agent to decide when and how to call it.

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 adds meaning for breakage_distance_m (explains why to increase it for sparse GPS) and vehicle_profile (implies costing=truck), and clarifies the shape parameter's optional time field. These enrich the schema without redundancy.

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?

The description opens with a clear, specific verb–resource pairing ('return road/network attributes for matched traces') and enumerates the exact attributes returned (road names, classes, speed limits, surfaces, truck-route flags, segment lengths, confidence score). It explicitly distinguishes itself from the sibling map_match ('For just the matched route line, use map_match'), so an agent can differentiate without opening schemas.

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

Usage Guidelines5/5

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

The description states explicit use cases ('audit what roads a vehicle actually used – speed-limit compliance, truck-route adherence, surface checks') and explicitly names the alternative for route geometry. It also gives operational guidance on when to adjust breakage_distance_m and how to handle the 200 km limit, which is actionable context.

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

trafficA
Read-only
Inspect

Retrieve live traffic conditions, congestion, and speed for a location. Use when traffic is needed independently of routing — for corridor monitoring, area congestion, or incident checks. COVERAGE: live data for ~30 major US metros; returns degraded or empty values outside these areas. For rural coordinates, qualify the response (e.g. 'no live traffic coverage here — showing free-flow speeds').

ParametersJSON Schema
NameRequiredDescriptionDefault
latYesLatitude
lonYesLongitude
unitsNoSpeed units — auto-detected from location (mph in US/UK, km/h elsewhere). Override if needed. Accepts 'km'/'mi' as aliases.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
display_hintNo

TDQS

A4.7/5.0
Behavior5/5

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

The description goes well beyond annotations by disclosing coverage limitations (~30 major US metros), degraded/empty values outside those areas, and instructing to qualify responses for rural locations. This adds significant behavioral context that annotations (readOnlyHint, openWorldHint, idempotentHint) do not cover.

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 three sentences, each serving a distinct purpose: core function, usage context, and coverage caveat. It is front-loaded and concise, with no filler.

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

Completeness5/5

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

For a simple location-based tool, the description covers the essential caveat (coverage limitation) and usage context. An output schema exists, so return values are already specified, and annotations provide safety hints. The description is complete enough for an agent to select and invoke 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 parameters are already well-documented (lat/lon, units with auto-detection and aliases). The description adds no meaningful parameter information beyond the schema, so the baseline score of 3 applies.

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?

The description clearly states the tool retrieves live traffic conditions, congestion, and speed for a location, with a specific verb and resource. It distinguishes this tool from siblings by noting 'independently of routing', which separates it from directions and routing-focused tools.

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

Usage Guidelines5/5

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

Explicitly states when to use the tool ('when traffic is needed independently of routing') and provides use cases (corridor monitoring, area congestion, incident checks). It also includes guidance for handling rural coordinates, which shows thoughtful usage instructions beyond alternatives.

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

weatherA
Read-only
Inspect

Get current and forecast weather for a location, including severe weather alerts and minute-by-minute precipitation. Use for destination conditions, travel planning, or route risk assessment.

ParametersJSON Schema
NameRequiredDescriptionDefault
latNoLatitude
lonNoLongitude
unitsNoTemperature/wind units (default: imperial)
locationNoPlace name or address (will be geocoded)
forecast_daysNoForecast days 1-16 (default 5)
include_alertsNoInclude severe weather alerts and warnings (default: true)
include_forecastNoInclude multi-day hourly forecast
include_minutelyNoInclude minute-by-minute precipitation for next 60 min

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsNo
alertsNo
geojsonNo
metricsNo
summaryNoMap of scalar facts the LLM should surface verbatim
alerts_errorNo
display_hintNo

TDQS

A4.2/5.0
Behavior4/5

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

Annotations declare readOnlyHint=true and openWorldHint=true, so the safety profile is already known. The description adds useful behavioral detail beyond annotations by specifying that the response includes current conditions, forecasts, severe alerts, and minutely precipitation. It does not contradict annotations and gives the agent a clear sense of the tool's data scope.

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 two sentences with no filler. The first sentence states the core function and key included data; the second provides concrete use cases. 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?

The description is complete enough given the annotations, 100% schema coverage, and the presence of an output schema. It names the core data products and use cases. It does not explicitly discuss rate limits, fallback behavior when no location is supplied, or exact return structure, but these are either covered by annotations/schema or are not required for calling the tool.

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 every parameter already has a meaningful description. The tool description adds general context about location and weather features but does not explain parameter nuances such as how to choose between lat/lon and the geocoded 'location' parameter, which is acceptable because the schema already covers these.

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?

The description states a specific action ('Get current and forecast weather') on a clear resource ('a location') and explicitly names notable outputs ('severe weather alerts', 'minute-by-minute precipitation'). This makes the tool's function immediately identifiable and distinct from the broader sibling list.

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?

The description gives clear use cases: 'destination conditions, travel planning, or route risk assessment.' It does not mention explicitly when not to use the tool or name alternative siblings, but the use-case framing is sufficient for an agent to select it appropriately in most contexts.

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. 1 tool update
    • Changedissue_api_key9 fields changed
      • removedOutput schema / properties / api_key
        Removed value: -{
        -  "description": "One-time API key secret. Returned only on successful creation, in both structuredContent.api_key and content[0].text. Save this key now. It is shown once. ThinAir authenticates using a hash of the key. Matches AWS IAM / Stripe / GitHub PAT one-time-reveal semantics.",
        -  "type": "string"
        -}
      • addedOutput schema / properties / console_url
        Added value: +{
        +  "description": "Link to the signed-in ThinAir Geo console, where the owner creates an API key and sees it once in their own browser. This tool never returns a key.",
        +  "type": "string"
        +}
      • removedOutput schema / properties / credential_returned_once
        Removed value: -{
        -  "type": "boolean"
        -}
      • addedOutput schema / properties / instructions
        Added value: +{
        +  "description": "How to create the key in the console and send it (Authorization: Bearer). Surface to the user as written.",
        +  "type": "string"
        +}
      • removedOutput schema / properties / key_id
        Removed value: -{
        -  "description": "Non-secret fingerprint of the issued key. Safe to log and surface in UI.",
        -  "type": "string"
        -}
      • removedOutput schema / properties / previous_keys_retire_at
        Removed value: -{
        -  "description": "ISO 8601 instant when the previous keys stop working (one hour after this mint). Present only when previous_keys_retiring > 0. Update anything still using them before this time.",
        -  "type": "string"
        -}
      • removedOutput schema / properties / previous_keys_retiring
        Removed value: -{
        -  "description": "How many previously-live keys this mint scheduled to retire. issue_api_key rotates: after the grace window the returned key is the only live key on the account. 0 means there was nothing else.",
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedOutput schema / properties / usage
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / user
        Removed value: -{
        -  "type": "string"
        -}
  2. 1 tool update
    • Changedissue_api_key1 field changed
      • changedOutput schema / properties / api_key / description
        Previous value: -"One-time API key secret. Returned only on successful creation, in both structuredContent.api_key and content[0].text — save it immediately. The server stores only sha-256 of the secret; once this response is lost, the key is unrecoverable and must be rotated. Matches AWS IAM / Stripe / GitHub PAT one-time-reveal semantics."New value: +"One-time API key secret. Returned only on successful creation, in both structuredContent.api_key and content[0].text. Save this key now. It is shown once. ThinAir authenticates using a hash of the key. Matches AWS IAM / Stripe / GitHub PAT one-time-reveal semantics."
  3. 1 tool update
    • Changedlocate4 fields changed
      • changedOutput schema / properties / meta / additionalProperties
        Previous value: -{}New value: +true
      • addedOutput schema / properties / meta / properties
        Added value: +{
        +  "degraded": {
        +    "description": "Present and true only when `road_status` is `unavailable`: the road part of the answer is missing; the rest is real.",
        +    "type": "boolean"
        +  }
        +}
      • addedOutput schema / properties / retryable
        Added value: +{
        +  "description": "Present and true only when `road_status` is `unavailable`: the same call may succeed shortly.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / road_status
        Added value: +{
        +  "description": "Why `road` is what it is. `matched`: a routable road was found. `no_road_nearby`: the lookup answered and found no routable road near the point for this travel profile. `unavailable`: the road lookup could not be answered right now; this says nothing about the point, `retryable` is true, and the timezone and any requested elevation are still looked up separately.",
        +  "enum": [
        +    "matched",
        +    "no_road_nearby",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
  4. 1 tool update
    • Changedreverse_geocode1 field changed
      • changedInput schema / properties / size / description
        Previous value: -"Number of nearby candidates (default 3, max 40)"New value: +"Number of nearby candidates (default 5, max 40)"
  5. 1 tool update
    • Changeddirections5 fields changed
      • changedOutput schema / properties / traffic_provenance / properties / freshness_seconds / description
        Previous value: -"Age, in seconds, of the oldest traffic observation behind this response. Null when the traffic provider did not report an observation age."New value: +"DEPRECATED since 2026-09-24, always null — same reason as `source_as_of`. See `retrieval_age_seconds` for the acquisition age ThinAir CAN report honestly. Will be removed in /v2."
      • changedOutput schema / properties / traffic_provenance / properties / outcome / description
        Previous value: -"Neutral, stable reason code for what happened to traffic evidence on this request. `TRAFFIC_DISABLED`: no traffic evidence was sought. `PROVIDER_DISABLED`: evidence was sought but the traffic backend was not configured. `QUOTA_EXHAUSTED`: the traffic backend's spend allotment was exhausted. `NO_SEGMENT_MATCH`: the backend answered but no sample matched a live road segment. `INSUFFICIENT_COVERAGE`: the backend reported no sensor coverage for the sampled area. `STALE_EVIDENCE`: an adjustment was computed, but the oldest observation behind it is older than this response is willing to call current. `UPSTREAM_ERROR`: a configured backend or network failure prevented reading all requested traffic evidence. `APPLIED`: an adjustment was computed and reached this response; inspect the nullable freshness and source-time fields to determine whether its observation age is known. Material failure codes take precedence over `APPLIED` when only partial evidence adjusted the duration; `duration_influenced` remains true in that case."New value: +"Neutral, stable reason code for what happened to traffic evidence on this request. `TRAFFIC_DISABLED`: no traffic evidence was sought. `PROVIDER_DISABLED`: evidence was sought but the traffic backend was not configured. `QUOTA_EXHAUSTED`: the traffic backend's spend allotment was exhausted. `NO_SEGMENT_MATCH`: the backend answered but no sample matched a live road segment. `INSUFFICIENT_COVERAGE`: the backend reported no sensor coverage for the sampled area. `STALE_EVIDENCE`: an adjustment was computed, but the evidence behind it was fetched more than 30 minutes ago because the provider could not refresh it. `UPSTREAM_ERROR`: a configured backend or network failure prevented reading all requested traffic evidence. `APPLIED`: an adjustment was computed and reached this response; inspect `retrieved_at` / `retrieval_age_seconds` to see how old the evidence behind it is (acquisition age — this traffic source reports no observation time, see those fields' own descriptions). Material failure codes take precedence over `APPLIED` when only partial evidence adjusted the duration; `duration_influenced` remains true in that case."
      • changedOutput schema / properties / traffic_provenance / properties / retrieval_age_seconds / description
        Previous value: -"Age, in seconds, of the oldest retrieved traffic tile bytes used by this response. This is cache/acquisition age, not traffic-observation freshness. Null for point traffic or when tile cache metadata is unavailable."New value: +"Age, in seconds, of `retrieved_at` — how long ago ThinAir fetched the traffic evidence behind this response (point or tile). This is acquisition/cache age, not traffic-observation freshness. Null under the same condition as `retrieved_at`."
      • changedOutput schema / properties / traffic_provenance / properties / retrieved_at / description
        Previous value: -"ISO 8601 time when the oldest traffic tile bytes used by this response were retrieved or cached. This is acquisition metadata, not the time the traffic was observed. Null for point traffic or when tile cache metadata is unavailable."New value: +"ISO 8601 time when ThinAir fetched the traffic evidence behind this response (point or tile). This is acquisition metadata, not the time the traffic was observed — the traffic source reports no observation time (see `source_as_of`). Null when no consulted sample's acquisition time was determinable."
      • changedOutput schema / properties / traffic_provenance / properties / source_as_of / description
        Previous value: -"ISO 8601 time at which the traffic observations behind this response were made. Null when the traffic provider did not report an observation time."New value: +"DEPRECATED since 2026-09-24, always null. The traffic source provides no observation timestamp, so this field can never be filled honestly. See `retrieved_at` for when ThinAir fetched the traffic evidence (not when it was observed). Will be removed in /v2."
  6. 2 tool updates
    • Changedmap_match4 fields changed
      • addedInput schema / properties / breakage_distance_m
        Added value: +{
        +  "description": "Maximum gap, in meters, between consecutive fixes before the trace is split into separate sections (100–20000). Increase for sparsely-reported GPS, such as fleet units reporting every several minutes on a highway. Optional — omitted uses the default.",
        +  "maximum": 20000,
        +  "minimum": 100,
        +  "type": "integer"
        +}
      • changedOutput schema / properties / meta / additionalProperties
        Previous value: -{}New value: +true
      • addedOutput schema / properties / meta / properties
        Added value: +{
        +  "breakage_distance_m": {
        +    "description": "Echoes the breakage_distance_m the caller requested, for confirmation — present only when the caller set it. This is the value SENT to the matcher, not a claim about what it did with it.",
        +    "type": "integer"
        +  },
        +  "point_count": {
        +    "type": "integer"
        +  },
        +  "upstream_ms": {
        +    "type": "number"
        +  }
        +}
      • addedOutput schema / properties / meta / required
        Added value: +[
        +  "upstream_ms",
        +  "point_count"
        +]
    • Changedtrace_attributes4 fields changed
      • addedInput schema / properties / breakage_distance_m
        Added value: +{
        +  "description": "Maximum gap, in meters, between consecutive fixes before the trace is split into separate sections (100–20000). Increase for sparsely-reported GPS, such as fleet units reporting every several minutes on a highway. Optional — omitted uses the default.",
        +  "maximum": 20000,
        +  "minimum": 100,
        +  "type": "integer"
        +}
      • changedOutput schema / properties / meta / additionalProperties
        Previous value: -{}New value: +true
      • addedOutput schema / properties / meta / properties
        Added value: +{
        +  "breakage_distance_m": {
        +    "description": "Echoes the breakage_distance_m the caller requested, for confirmation — present only when the caller set it. This is the value SENT to the matcher, not a claim about what it did with it.",
        +    "type": "integer"
        +  },
        +  "point_count": {
        +    "type": "integer"
        +  },
        +  "upstream_ms": {
        +    "type": "number"
        +  }
        +}
      • addedOutput schema / properties / meta / required
        Added value: +[
        +  "upstream_ms",
        +  "point_count"
        +]
  7. 2 tool updates
    • Changeddistance_matrix2 fields changed
      • addedOutput schema / properties / duration_basis
        Added value: +{
        +  "const": "static_road_speeds",
        +  "description": "How matrix durations were computed. `static_road_speeds` (the only value today): durations come from the road network's own speed data — posted limits and road-class defaults — never from historical or live traffic. Use `directions` for a traffic-adjusted ETA between two specific points.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / traffic_applied
        Added value: +{
        +  "const": false,
        +  "description": "Whether live or historical traffic influenced any matrix duration. Always false today — see `duration_basis`.",
        +  "type": "boolean"
        +}
    • Changedmap_match4 fields changed
      • changedOutput schema / properties / confidence / description
        Previous value: -"0–1: fraction of input GPS points within the snap tolerance of the matched route"New value: +"0–1: fraction of input GPS points within the snap tolerance of the matched route. A distance heuristic: it ignores point order and which parallel roadway was matched. For the matcher's own per-point result use `match_status` / `coverage`."
      • addedOutput schema / properties / coverage
        Added value: +{
        +  "additionalProperties": true,
        +  "description": "Per-point coverage of the trace from the matcher's own per-point status — independent of the distance-based `confidence`. Every key is always present.",
        +  "properties": {
        +    "interpolated_count": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Input points the matcher placed on the road network by interpolating between matched neighbours; counted as covered. null when unavailable."
        +    },
        +    "matched_count": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Input points the matcher placed on the road network directly. null when unavailable."
        +    },
        +    "point_count": {
        +      "description": "Number of input GPS points",
        +      "type": "integer"
        +    },
        +    "ratio": {
        +      "description": "0–1: (matched_count + interpolated_count) / point_count, rounded down to 3 decimals so a partial trace never reads 1. null when unavailable.",
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "route_sections": {
        +      "description": "Number of disjoint sections the match broke into (1 = continuous). When greater than 1, the returned geometry, distance and duration cover only the FIRST section — split the trace at the break and match the parts separately.",
        +      "type": "integer"
        +    },
        +    "unavailable_reason": {
        +      "anyOf": [
        +        {
        +          "enum": [
        +            "upstream_error",
        +            "timeout",
        +            "no_point_status",
        +            "point_count_mismatch",
        +            "unknown_point_type"
        +          ],
        +          "type": "string"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Why the per-point counts and `match_status` are null: `upstream_error` (the per-point check failed), `timeout` (it did not answer in time), `no_point_status` (it answered without per-point results), `point_count_mismatch` (its results did not line up one-to-one with the input points), `unknown_point_type` (it reported a status this API does not recognise). null when coverage is available."
        +    },
        +    "unmatched_count": {
        +      "anyOf": [
        +        {
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Input points the matcher could not place on the road network. null when unavailable."
        +    },
        +    "unmatched_ranges": {
        +      "anyOf": [
        +        {
        +          "items": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "end_index": {
        +                "description": "0-based index of the last unmatched input point in this run (inclusive)",
        +                "type": "integer"
        +              },
        +              "point_count": {
        +                "description": "Number of input points in this run",
        +                "type": "integer"
        +              },
        +              "start_index": {
        +                "description": "0-based index of the first unmatched input point in this run",
        +                "type": "integer"
        +              }
        +            },
        +            "required": [
        +              "start_index",
        +              "end_index",
        +              "point_count"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Contiguous runs of unmatched input points, as 0-based inclusive index ranges into `shape`, in trace order. Empty when every point was covered; null when unavailable."
        +    }
        +  },
        +  "required": [
        +    "point_count",
        +    "matched_count",
        +    "interpolated_count",
        +    "unmatched_count",
        +    "ratio",
        +    "unmatched_ranges",
        +    "route_sections",
        +    "unavailable_reason"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / match_status
        Added value: +{
        +  "anyOf": [
        +    {
        +      "enum": [
        +        "full",
        +        "partial",
        +        "none"
        +      ],
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Whole-trace match status from the matcher's own per-point results. `full`: every input point was matched or interpolated onto the road network AND the match is one continuous section. `none`: no input point was matched or interpolated. `partial`: anything else — some points unmatched, or the match broke into more than one section. null when the per-point check could not be completed; `coverage.unavailable_reason` says why. Gate on this field, not on `matched`."
        +}
      • addedOutput schema / properties / matched / description
        Added value: +"True when a route was returned for the trace. It does NOT mean the whole trace matched — use `match_status`."
  8. 1 tool update
    • Changedsearch_places8 fields changed
      • addedInput schema / properties / center / properties / lat / $ref
        Added value: +"#/properties/lat"
      • removedInput schema / properties / center / properties / lat / maximum
        Removed value: -90
      • removedInput schema / properties / center / properties / lat / minimum
        Removed value: --90
      • removedInput schema / properties / center / properties / lat / type
        Removed value: -"number"
      • addedInput schema / properties / center / properties / lon / $ref
        Added value: +"#/properties/lon"
      • removedInput schema / properties / center / properties / lon / maximum
        Removed value: -180
      • removedInput schema / properties / center / properties / lon / minimum
        Removed value: --180
      • removedInput schema / properties / center / properties / lon / type
        Removed value: -"number"
  9. 1 tool update
    • Changedweather1 field changed
      • addedOutput schema / properties / alerts_error
        Added value: +{
        +  "type": "string"
        +}
  10. 4 tool updates
    • Changedgeocode1 field changed
      • changedOutput schema / properties / items / items / properties / postal_code / description
        Previous value: -"An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."New value: +"An eligible US ZIP5 read from the selected result's own postal-code field. While origin enforcement is active this field is emitted ONLY when the engine stamped the value as coming from the address record itself (`source_record` provenance); a value inherited from a parent area, or a result cached before that evidence existed, is omitted rather than emitted without provenance — so an absent ZIP under enforcement means \"not proven for this record\", not \"no such ZIP\". Provenance describes only WHERE the value came from. It is not a postal operator check of any kind — no certification, no address-quality rating, and no statement about whether mail would arrive — so a syntactically correct, correctly-sourced value can still be wrong for the address. Also omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."
    • Changedgeocode_structured1 field changed
      • changedOutput schema / properties / items / items / properties / postal_code / description
        Previous value: -"An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."New value: +"An eligible US ZIP5 read from the selected result's own postal-code field. While origin enforcement is active this field is emitted ONLY when the engine stamped the value as coming from the address record itself (`source_record` provenance); a value inherited from a parent area, or a result cached before that evidence existed, is omitted rather than emitted without provenance — so an absent ZIP under enforcement means \"not proven for this record\", not \"no such ZIP\". Provenance describes only WHERE the value came from. It is not a postal operator check of any kind — no certification, no address-quality rating, and no statement about whether mail would arrive — so a syntactically correct, correctly-sourced value can still be wrong for the address. Also omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."
    • Changedresolve_intersection1 field changed
      • changedOutput schema / properties / feature / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "address_components": {
        -        "additionalProperties": false,
        -        "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        -        "properties": {
        -          "country_code": {
        -            "type": "string"
        -          },
        -          "house_number": {
        -            "type": "string"
        -          },
        -          "locality": {
        -            "type": "string"
        -          },
        -          "postal_code": {
        -            "type": "string"
        -          },
        -          "region_code": {
        -            "type": "string"
        -          },
        -          "region_name": {
        -            "type": "string"
        -          },
        -          "street": {
        -            "type": "string"
        -          },
        -          "unit": {
        -            "type": "string"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "address_evidence": {
        -        "additionalProperties": false,
        -        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        -        "properties": {
        -          "house_number": {
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "locality": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "postal_code": {
        -            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "region": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "street": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          }
        -        },
        -        "required": [
        -          "house_number",
        -          "street",
        -          "locality",
        -          "region",
        -          "postal_code"
        -        ],
        -        "type": "object"
        -      },
        -      "address_line1": {
        -        "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        -        "type": "string"
        -      },
        -      "address_line2": {
        -        "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        -        "type": "string"
        -      },
        -      "confidence": {
        -        "type": "number"
        -      },
        -      "confidence_scope": {
        -        "const": "query_to_candidate",
        -        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        -        "type": "string"
        -      },
        -      "cross_street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "cross_street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "formatted_address": {
        -        "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        -        "type": "string"
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "intersection_precision": {
        -        "enum": [
        -          "geometric_crossing",
        -          "tangent_intersection",
        -          "centroid_cluster",
        -          "approximate"
        -        ],
        -        "type": "string"
        -      },
        -      "intersection_type": {
        -        "enum": [
        -          "corner",
        -          "interchange"
        -        ],
        -        "type": "string"
        -      },
        -      "label": {
        -        "type": "string"
        -      },
        -      "lat": {
        -        "type": "number"
        -      },
        -      "layer": {
        -        "type": "string"
        -      },
        -      "lon": {
        -        "type": "number"
        -      },
        -      "method": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "place_type": {
        -        "type": "string"
        -      },
        -      "postal_code": {
        -        "description": "An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        -        "pattern": "^[0-9]{5}$",
        -        "type": "string"
        -      },
        -      "postal_input_match": {
        -        "description": "STRUCTURED GEOCODING ONLY (`geocode_structured` / `POST /v1/search/structured`); absent from free-text geocoding. Whether the postcode YOU SUBMITTED agrees with this candidate's own postcode — `match` (same five-digit value), `conflict` (they differ), `unavailable` (no comparison was possible). This compares two values already in hand: no lookup, no external reference, and your query text is never parsed to find one. `conflict` does NOT say which side is wrong — your input may name a neighbouring area, the candidate may be a near-miss, or the record's own value may be stale; treat it as a prompt to ask a human, never as a correction to apply automatically. The candidate side counts only when its postcode came from the address record itself; one inherited from a parent area yields `unavailable` rather than a misleading verdict. `unavailable` also covers: nothing submitted, a submitted value not readable as a US five-digit code, and results cached before this field existed.",
        -        "enum": [
        -          "match",
        -          "conflict",
        -          "unavailable"
        -        ],
        -        "type": "string"
        -      },
        -      "street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "address_components": {
        +        "additionalProperties": false,
        +        "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        +        "properties": {
        +          "country_code": {
        +            "type": "string"
        +          },
        +          "house_number": {
        +            "type": "string"
        +          },
        +          "locality": {
        +            "type": "string"
        +          },
        +          "postal_code": {
        +            "type": "string"
        +          },
        +          "region_code": {
        +            "type": "string"
        +          },
        +          "region_name": {
        +            "type": "string"
        +          },
        +          "street": {
        +            "type": "string"
        +          },
        +          "unit": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "address_evidence": {
        +        "additionalProperties": false,
        +        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +        "properties": {
        +          "house_number": {
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "locality": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "postal_code": {
        +            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "region": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "street": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          }
        +        },
        +        "required": [
        +          "house_number",
        +          "street",
        +          "locality",
        +          "region",
        +          "postal_code"
        +        ],
        +        "type": "object"
        +      },
        +      "address_line1": {
        +        "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        +        "type": "string"
        +      },
        +      "address_line2": {
        +        "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        +        "type": "string"
        +      },
        +      "confidence": {
        +        "type": "number"
        +      },
        +      "confidence_scope": {
        +        "const": "query_to_candidate",
        +        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +        "type": "string"
        +      },
        +      "cross_street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "cross_street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "formatted_address": {
        +        "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "intersection_precision": {
        +        "enum": [
        +          "geometric_crossing",
        +          "tangent_intersection",
        +          "centroid_cluster",
        +          "approximate"
        +        ],
        +        "type": "string"
        +      },
        +      "intersection_type": {
        +        "enum": [
        +          "corner",
        +          "interchange"
        +        ],
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "lat": {
        +        "type": "number"
        +      },
        +      "layer": {
        +        "type": "string"
        +      },
        +      "lon": {
        +        "type": "number"
        +      },
        +      "method": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "place_type": {
        +        "type": "string"
        +      },
        +      "postal_code": {
        +        "description": "An eligible US ZIP5 read from the selected result's own postal-code field. While origin enforcement is active this field is emitted ONLY when the engine stamped the value as coming from the address record itself (`source_record` provenance); a value inherited from a parent area, or a result cached before that evidence existed, is omitted rather than emitted without provenance — so an absent ZIP under enforcement means \"not proven for this record\", not \"no such ZIP\". Provenance describes only WHERE the value came from. It is not a postal operator check of any kind — no certification, no address-quality rating, and no statement about whether mail would arrive — so a syntactically correct, correctly-sourced value can still be wrong for the address. Also omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +        "pattern": "^[0-9]{5}$",
        +        "type": "string"
        +      },
        +      "postal_input_match": {
        +        "description": "STRUCTURED GEOCODING ONLY (`geocode_structured` / `POST /v1/search/structured`); absent from free-text geocoding. Whether the postcode YOU SUBMITTED agrees with this candidate's own postcode — `match` (same five-digit value), `conflict` (they differ), `unavailable` (no comparison was possible). This compares two values already in hand: no lookup, no external reference, and your query text is never parsed to find one. `conflict` does NOT say which side is wrong — your input may name a neighbouring area, the candidate may be a near-miss, or the record's own value may be stale; treat it as a prompt to ask a human, never as a correction to apply automatically. The candidate side counts only when its postcode came from the address record itself; one inherited from a parent area yields `unavailable` rather than a misleading verdict. `unavailable` also covers: nothing submitted, a submitted value not readable as a US five-digit code, and results cached before this field existed.",
        +        "enum": [
        +          "match",
        +          "conflict",
        +          "unavailable"
        +        ],
        +        "type": "string"
        +      },
        +      "street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedreverse_geocode1 field changed
      • changedOutput schema / properties / items / items / properties / postal_code / description
        Previous value: -"An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."New value: +"An eligible US ZIP5 read from the selected result's own postal-code field. While origin enforcement is active this field is emitted ONLY when the engine stamped the value as coming from the address record itself (`source_record` provenance); a value inherited from a parent area, or a result cached before that evidence existed, is omitted rather than emitted without provenance — so an absent ZIP under enforcement means \"not proven for this record\", not \"no such ZIP\". Provenance describes only WHERE the value came from. It is not a postal operator check of any kind — no certification, no address-quality rating, and no statement about whether mail would arrive — so a syntactically correct, correctly-sourced value can still be wrong for the address. Also omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."
  11. 4 tool updates
    • Changedgeocode2 fields changed
      • addedOutput schema / properties / items / items / properties / address_components / properties / region_name
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / postal_input_match
        Added value: +{
        +  "description": "STRUCTURED GEOCODING ONLY (`geocode_structured` / `POST /v1/search/structured`); absent from free-text geocoding. Whether the postcode YOU SUBMITTED agrees with this candidate's own postcode — `match` (same five-digit value), `conflict` (they differ), `unavailable` (no comparison was possible). This compares two values already in hand: no lookup, no external reference, and your query text is never parsed to find one. `conflict` does NOT say which side is wrong — your input may name a neighbouring area, the candidate may be a near-miss, or the record's own value may be stale; treat it as a prompt to ask a human, never as a correction to apply automatically. The candidate side counts only when its postcode came from the address record itself; one inherited from a parent area yields `unavailable` rather than a misleading verdict. `unavailable` also covers: nothing submitted, a submitted value not readable as a US five-digit code, and results cached before this field existed.",
        +  "enum": [
        +    "match",
        +    "conflict",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
    • Changedgeocode_structured2 fields changed
      • addedOutput schema / properties / items / items / properties / address_components / properties / region_name
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / postal_input_match
        Added value: +{
        +  "description": "STRUCTURED GEOCODING ONLY (`geocode_structured` / `POST /v1/search/structured`); absent from free-text geocoding. Whether the postcode YOU SUBMITTED agrees with this candidate's own postcode — `match` (same five-digit value), `conflict` (they differ), `unavailable` (no comparison was possible). This compares two values already in hand: no lookup, no external reference, and your query text is never parsed to find one. `conflict` does NOT say which side is wrong — your input may name a neighbouring area, the candidate may be a near-miss, or the record's own value may be stale; treat it as a prompt to ask a human, never as a correction to apply automatically. The candidate side counts only when its postcode came from the address record itself; one inherited from a parent area yields `unavailable` rather than a misleading verdict. `unavailable` also covers: nothing submitted, a submitted value not readable as a US five-digit code, and results cached before this field existed.",
        +  "enum": [
        +    "match",
        +    "conflict",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
    • Changedresolve_intersection1 field changed
      • changedOutput schema / properties / feature / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "address_components": {
        -        "additionalProperties": false,
        -        "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        -        "properties": {
        -          "country_code": {
        -            "type": "string"
        -          },
        -          "house_number": {
        -            "type": "string"
        -          },
        -          "locality": {
        -            "type": "string"
        -          },
        -          "postal_code": {
        -            "type": "string"
        -          },
        -          "region_code": {
        -            "type": "string"
        -          },
        -          "street": {
        -            "type": "string"
        -          },
        -          "unit": {
        -            "type": "string"
        -          }
        -        },
        -        "type": "object"
        -      },
        -      "address_evidence": {
        -        "additionalProperties": false,
        -        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        -        "properties": {
        -          "house_number": {
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "locality": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "postal_code": {
        -            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "region": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "street": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          }
        -        },
        -        "required": [
        -          "house_number",
        -          "street",
        -          "locality",
        -          "region",
        -          "postal_code"
        -        ],
        -        "type": "object"
        -      },
        -      "address_line1": {
        -        "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        -        "type": "string"
        -      },
        -      "address_line2": {
        -        "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        -        "type": "string"
        -      },
        -      "confidence": {
        -        "type": "number"
        -      },
        -      "confidence_scope": {
        -        "const": "query_to_candidate",
        -        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        -        "type": "string"
        -      },
        -      "cross_street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "cross_street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "formatted_address": {
        -        "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        -        "type": "string"
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "intersection_precision": {
        -        "enum": [
        -          "geometric_crossing",
        -          "tangent_intersection",
        -          "centroid_cluster",
        -          "approximate"
        -        ],
        -        "type": "string"
        -      },
        -      "intersection_type": {
        -        "enum": [
        -          "corner",
        -          "interchange"
        -        ],
        -        "type": "string"
        -      },
        -      "label": {
        -        "type": "string"
        -      },
        -      "lat": {
        -        "type": "number"
        -      },
        -      "layer": {
        -        "type": "string"
        -      },
        -      "lon": {
        -        "type": "number"
        -      },
        -      "method": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "place_type": {
        -        "type": "string"
        -      },
        -      "postal_code": {
        -        "description": "An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        -        "pattern": "^[0-9]{5}$",
        -        "type": "string"
        -      },
        -      "street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "address_components": {
        +        "additionalProperties": false,
        +        "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        +        "properties": {
        +          "country_code": {
        +            "type": "string"
        +          },
        +          "house_number": {
        +            "type": "string"
        +          },
        +          "locality": {
        +            "type": "string"
        +          },
        +          "postal_code": {
        +            "type": "string"
        +          },
        +          "region_code": {
        +            "type": "string"
        +          },
        +          "region_name": {
        +            "type": "string"
        +          },
        +          "street": {
        +            "type": "string"
        +          },
        +          "unit": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "address_evidence": {
        +        "additionalProperties": false,
        +        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +        "properties": {
        +          "house_number": {
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "locality": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "postal_code": {
        +            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "region": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "street": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          }
        +        },
        +        "required": [
        +          "house_number",
        +          "street",
        +          "locality",
        +          "region",
        +          "postal_code"
        +        ],
        +        "type": "object"
        +      },
        +      "address_line1": {
        +        "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        +        "type": "string"
        +      },
        +      "address_line2": {
        +        "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        +        "type": "string"
        +      },
        +      "confidence": {
        +        "type": "number"
        +      },
        +      "confidence_scope": {
        +        "const": "query_to_candidate",
        +        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +        "type": "string"
        +      },
        +      "cross_street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "cross_street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "formatted_address": {
        +        "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "intersection_precision": {
        +        "enum": [
        +          "geometric_crossing",
        +          "tangent_intersection",
        +          "centroid_cluster",
        +          "approximate"
        +        ],
        +        "type": "string"
        +      },
        +      "intersection_type": {
        +        "enum": [
        +          "corner",
        +          "interchange"
        +        ],
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "lat": {
        +        "type": "number"
        +      },
        +      "layer": {
        +        "type": "string"
        +      },
        +      "lon": {
        +        "type": "number"
        +      },
        +      "method": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "place_type": {
        +        "type": "string"
        +      },
        +      "postal_code": {
        +        "description": "An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +        "pattern": "^[0-9]{5}$",
        +        "type": "string"
        +      },
        +      "postal_input_match": {
        +        "description": "STRUCTURED GEOCODING ONLY (`geocode_structured` / `POST /v1/search/structured`); absent from free-text geocoding. Whether the postcode YOU SUBMITTED agrees with this candidate's own postcode — `match` (same five-digit value), `conflict` (they differ), `unavailable` (no comparison was possible). This compares two values already in hand: no lookup, no external reference, and your query text is never parsed to find one. `conflict` does NOT say which side is wrong — your input may name a neighbouring area, the candidate may be a near-miss, or the record's own value may be stale; treat it as a prompt to ask a human, never as a correction to apply automatically. The candidate side counts only when its postcode came from the address record itself; one inherited from a parent area yields `unavailable` rather than a misleading verdict. `unavailable` also covers: nothing submitted, a submitted value not readable as a US five-digit code, and results cached before this field existed.",
        +        "enum": [
        +          "match",
        +          "conflict",
        +          "unavailable"
        +        ],
        +        "type": "string"
        +      },
        +      "street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedreverse_geocode2 fields changed
      • addedOutput schema / properties / items / items / properties / address_components / properties / region_name
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / postal_input_match
        Added value: +{
        +  "description": "STRUCTURED GEOCODING ONLY (`geocode_structured` / `POST /v1/search/structured`); absent from free-text geocoding. Whether the postcode YOU SUBMITTED agrees with this candidate's own postcode — `match` (same five-digit value), `conflict` (they differ), `unavailable` (no comparison was possible). This compares two values already in hand: no lookup, no external reference, and your query text is never parsed to find one. `conflict` does NOT say which side is wrong — your input may name a neighbouring area, the candidate may be a near-miss, or the record's own value may be stale; treat it as a prompt to ask a human, never as a correction to apply automatically. The candidate side counts only when its postcode came from the address record itself; one inherited from a parent area yields `unavailable` rather than a misleading verdict. `unavailable` also covers: nothing submitted, a submitted value not readable as a US five-digit code, and results cached before this field existed.",
        +  "enum": [
        +    "match",
        +    "conflict",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
  12. 4 tool updates
    • Changedgeocode5 fields changed
      • addedOutput schema / properties / items / items / properties / address_components
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        +  "properties": {
        +    "country_code": {
        +      "type": "string"
        +    },
        +    "house_number": {
        +      "type": "string"
        +    },
        +    "locality": {
        +      "type": "string"
        +    },
        +    "postal_code": {
        +      "type": "string"
        +    },
        +    "region_code": {
        +      "type": "string"
        +    },
        +    "street": {
        +      "type": "string"
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / items / items / properties / address_line1
        Added value: +{
        +  "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / address_line2
        Added value: +{
        +  "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / formatted_address
        Added value: +{
        +  "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / items / items / properties / postal_code / description
        Previous value: -"Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."New value: +"An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."
    • Changedgeocode_structured5 fields changed
      • addedOutput schema / properties / items / items / properties / address_components
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        +  "properties": {
        +    "country_code": {
        +      "type": "string"
        +    },
        +    "house_number": {
        +      "type": "string"
        +    },
        +    "locality": {
        +      "type": "string"
        +    },
        +    "postal_code": {
        +      "type": "string"
        +    },
        +    "region_code": {
        +      "type": "string"
        +    },
        +    "street": {
        +      "type": "string"
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / items / items / properties / address_line1
        Added value: +{
        +  "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / address_line2
        Added value: +{
        +  "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / formatted_address
        Added value: +{
        +  "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / items / items / properties / postal_code / description
        Previous value: -"Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."New value: +"An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."
    • Changedresolve_intersection1 field changed
      • changedOutput schema / properties / feature / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "address_evidence": {
        -        "additionalProperties": false,
        -        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        -        "properties": {
        -          "house_number": {
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "locality": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "postal_code": {
        -            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "region": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "street": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          }
        -        },
        -        "required": [
        -          "house_number",
        -          "street",
        -          "locality",
        -          "region",
        -          "postal_code"
        -        ],
        -        "type": "object"
        -      },
        -      "confidence": {
        -        "type": "number"
        -      },
        -      "confidence_scope": {
        -        "const": "query_to_candidate",
        -        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        -        "type": "string"
        -      },
        -      "cross_street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "cross_street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "intersection_precision": {
        -        "enum": [
        -          "geometric_crossing",
        -          "tangent_intersection",
        -          "centroid_cluster",
        -          "approximate"
        -        ],
        -        "type": "string"
        -      },
        -      "intersection_type": {
        -        "enum": [
        -          "corner",
        -          "interchange"
        -        ],
        -        "type": "string"
        -      },
        -      "label": {
        -        "type": "string"
        -      },
        -      "lat": {
        -        "type": "number"
        -      },
        -      "layer": {
        -        "type": "string"
        -      },
        -      "lon": {
        -        "type": "number"
        -      },
        -      "method": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "place_type": {
        -        "type": "string"
        -      },
        -      "postal_code": {
        -        "description": "Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        -        "pattern": "^[0-9]{5}$",
        -        "type": "string"
        -      },
        -      "street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "address_components": {
        +        "additionalProperties": false,
        +        "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        +        "properties": {
        +          "country_code": {
        +            "type": "string"
        +          },
        +          "house_number": {
        +            "type": "string"
        +          },
        +          "locality": {
        +            "type": "string"
        +          },
        +          "postal_code": {
        +            "type": "string"
        +          },
        +          "region_code": {
        +            "type": "string"
        +          },
        +          "street": {
        +            "type": "string"
        +          },
        +          "unit": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "address_evidence": {
        +        "additionalProperties": false,
        +        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +        "properties": {
        +          "house_number": {
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "locality": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "postal_code": {
        +            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "region": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "street": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          }
        +        },
        +        "required": [
        +          "house_number",
        +          "street",
        +          "locality",
        +          "region",
        +          "postal_code"
        +        ],
        +        "type": "object"
        +      },
        +      "address_line1": {
        +        "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        +        "type": "string"
        +      },
        +      "address_line2": {
        +        "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        +        "type": "string"
        +      },
        +      "confidence": {
        +        "type": "number"
        +      },
        +      "confidence_scope": {
        +        "const": "query_to_candidate",
        +        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +        "type": "string"
        +      },
        +      "cross_street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "cross_street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "formatted_address": {
        +        "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "intersection_precision": {
        +        "enum": [
        +          "geometric_crossing",
        +          "tangent_intersection",
        +          "centroid_cluster",
        +          "approximate"
        +        ],
        +        "type": "string"
        +      },
        +      "intersection_type": {
        +        "enum": [
        +          "corner",
        +          "interchange"
        +        ],
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "lat": {
        +        "type": "number"
        +      },
        +      "layer": {
        +        "type": "string"
        +      },
        +      "lon": {
        +        "type": "number"
        +      },
        +      "method": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "place_type": {
        +        "type": "string"
        +      },
        +      "postal_code": {
        +        "description": "An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +        "pattern": "^[0-9]{5}$",
        +        "type": "string"
        +      },
        +      "street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedreverse_geocode5 fields changed
      • addedOutput schema / properties / items / items / properties / address_components
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "The same US components the formatted string is built from. Every field is source-established or absent; nothing is inferred or back-filled.",
        +  "properties": {
        +    "country_code": {
        +      "type": "string"
        +    },
        +    "house_number": {
        +      "type": "string"
        +    },
        +    "locality": {
        +      "type": "string"
        +    },
        +    "postal_code": {
        +      "type": "string"
        +    },
        +    "region_code": {
        +      "type": "string"
        +    },
        +    "street": {
        +      "type": "string"
        +    },
        +    "unit": {
        +      "type": "string"
        +    }
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / items / items / properties / address_line1
        Added value: +{
        +  "description": "House number and street for an eligible US address result, composed from the result's own components — never parsed from the display label. Absent when the result is not a US street address.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / address_line2
        Added value: +{
        +  "description": "Unit or suite, only when the source record carries one. A unit supplied in your request is never echoed back here.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / items / items / properties / formatted_address
        Added value: +{
        +  "description": "Single-line US display form, e.g. `1600 Pennsylvania Avenue NW, Washington, DC 20500, USA`. The postal segment is present only when an eligible ZIP is; its absence never suppresses the street address.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / items / items / properties / postal_code / description
        Previous value: -"Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."New value: +"An eligible US ZIP5 normalized from the selected native result's available postal-code field; direct address-record origin is not yet guaranteed. Not checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied."
  13. 4 tool updates
    • Changedgeocode1 field changed
      • addedOutput schema / properties / items / items / properties / postal_code
        Added value: +{
        +  "description": "Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +  "pattern": "^[0-9]{5}$",
        +  "type": "string"
        +}
    • Changedgeocode_structured1 field changed
      • addedOutput schema / properties / items / items / properties / postal_code
        Added value: +{
        +  "description": "Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +  "pattern": "^[0-9]{5}$",
        +  "type": "string"
        +}
    • Changedresolve_intersection1 field changed
      • changedOutput schema / properties / feature / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "address_evidence": {
        -        "additionalProperties": false,
        -        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        -        "properties": {
        -          "house_number": {
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "locality": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "postal_code": {
        -            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        -            "enum": [
        -              "matched",
        -              "partial",
        -              "absent"
        -            ],
        -            "type": "string"
        -          },
        -          "region": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          },
        -          "street": {
        -            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        -          }
        -        },
        -        "required": [
        -          "house_number",
        -          "street",
        -          "locality",
        -          "region",
        -          "postal_code"
        -        ],
        -        "type": "object"
        -      },
        -      "confidence": {
        -        "type": "number"
        -      },
        -      "confidence_scope": {
        -        "const": "query_to_candidate",
        -        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        -        "type": "string"
        -      },
        -      "cross_street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "cross_street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "intersection_precision": {
        -        "enum": [
        -          "geometric_crossing",
        -          "tangent_intersection",
        -          "centroid_cluster",
        -          "approximate"
        -        ],
        -        "type": "string"
        -      },
        -      "intersection_type": {
        -        "enum": [
        -          "corner",
        -          "interchange"
        -        ],
        -        "type": "string"
        -      },
        -      "label": {
        -        "type": "string"
        -      },
        -      "lat": {
        -        "type": "number"
        -      },
        -      "layer": {
        -        "type": "string"
        -      },
        -      "lon": {
        -        "type": "number"
        -      },
        -      "method": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "place_type": {
        -        "type": "string"
        -      },
        -      "street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "address_evidence": {
        +        "additionalProperties": false,
        +        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +        "properties": {
        +          "house_number": {
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "locality": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "postal_code": {
        +            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "region": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "street": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          }
        +        },
        +        "required": [
        +          "house_number",
        +          "street",
        +          "locality",
        +          "region",
        +          "postal_code"
        +        ],
        +        "type": "object"
        +      },
        +      "confidence": {
        +        "type": "number"
        +      },
        +      "confidence_scope": {
        +        "const": "query_to_candidate",
        +        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +        "type": "string"
        +      },
        +      "cross_street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "cross_street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "intersection_precision": {
        +        "enum": [
        +          "geometric_crossing",
        +          "tangent_intersection",
        +          "centroid_cluster",
        +          "approximate"
        +        ],
        +        "type": "string"
        +      },
        +      "intersection_type": {
        +        "enum": [
        +          "corner",
        +          "interchange"
        +        ],
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "lat": {
        +        "type": "number"
        +      },
        +      "layer": {
        +        "type": "string"
        +      },
        +      "lon": {
        +        "type": "number"
        +      },
        +      "method": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "place_type": {
        +        "type": "string"
        +      },
        +      "postal_code": {
        +        "description": "Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +        "pattern": "^[0-9]{5}$",
        +        "type": "string"
        +      },
        +      "street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedreverse_geocode1 field changed
      • addedOutput schema / properties / items / items / properties / postal_code
        Added value: +{
        +  "description": "Five-digit ZIP taken from the postcode supplied with this address record. It is reported by that record's own data source and has not been checked against any postal operator's records, so a syntactically correct value can still be wrong for the address. Omitted when unavailable or unsuitable for five-digit form. US address results only. Distinct from `address_evidence.postal_code`, which is a presence STATUS rather than a value. On reverse geocoding this describes the RETURNED ADDRESS — it is not a postal assignment to the coordinate you supplied.",
        +  "pattern": "^[0-9]{5}$",
        +  "type": "string"
        +}
  14. 4 tool updates
    • Changedgeocode2 fields changed
      • addedOutput schema / properties / items / items / properties / address_evidence
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +  "properties": {
        +    "house_number": {
        +      "enum": [
        +        "matched",
        +        "partial",
        +        "absent"
        +      ],
        +      "type": "string"
        +    },
        +    "locality": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    },
        +    "postal_code": {
        +      "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +      "enum": [
        +        "matched",
        +        "partial",
        +        "absent"
        +      ],
        +      "type": "string"
        +    },
        +    "region": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    },
        +    "street": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    }
        +  },
        +  "required": [
        +    "house_number",
        +    "street",
        +    "locality",
        +    "region",
        +    "postal_code"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / items / items / properties / confidence_scope
        Added value: +{
        +  "const": "query_to_candidate",
        +  "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +  "type": "string"
        +}
    • Changedgeocode_structured2 fields changed
      • addedOutput schema / properties / items / items / properties / address_evidence
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +  "properties": {
        +    "house_number": {
        +      "enum": [
        +        "matched",
        +        "partial",
        +        "absent"
        +      ],
        +      "type": "string"
        +    },
        +    "locality": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    },
        +    "postal_code": {
        +      "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +      "enum": [
        +        "matched",
        +        "partial",
        +        "absent"
        +      ],
        +      "type": "string"
        +    },
        +    "region": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    },
        +    "street": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    }
        +  },
        +  "required": [
        +    "house_number",
        +    "street",
        +    "locality",
        +    "region",
        +    "postal_code"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / items / items / properties / confidence_scope
        Added value: +{
        +  "const": "query_to_candidate",
        +  "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +  "type": "string"
        +}
    • Changedresolve_intersection1 field changed
      • changedOutput schema / properties / feature / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "confidence": {
        -        "type": "number"
        -      },
        -      "cross_street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "cross_street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "intersection_precision": {
        -        "enum": [
        -          "geometric_crossing",
        -          "tangent_intersection",
        -          "centroid_cluster",
        -          "approximate"
        -        ],
        -        "type": "string"
        -      },
        -      "intersection_type": {
        -        "enum": [
        -          "corner",
        -          "interchange"
        -        ],
        -        "type": "string"
        -      },
        -      "label": {
        -        "type": "string"
        -      },
        -      "lat": {
        -        "type": "number"
        -      },
        -      "layer": {
        -        "type": "string"
        -      },
        -      "lon": {
        -        "type": "number"
        -      },
        -      "method": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "place_type": {
        -        "type": "string"
        -      },
        -      "street_kind": {
        -        "enum": [
        -          "street",
        -          "route"
        -        ],
        -        "type": "string"
        -      },
        -      "street_route": {
        -        "maxLength": 128,
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "address_evidence": {
        +        "additionalProperties": false,
        +        "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +        "properties": {
        +          "house_number": {
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "locality": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "postal_code": {
        +            "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +            "enum": [
        +              "matched",
        +              "partial",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "region": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          },
        +          "street": {
        +            "$ref": "#/properties/feature/anyOf/0/properties/address_evidence/properties/house_number"
        +          }
        +        },
        +        "required": [
        +          "house_number",
        +          "street",
        +          "locality",
        +          "region",
        +          "postal_code"
        +        ],
        +        "type": "object"
        +      },
        +      "confidence": {
        +        "type": "number"
        +      },
        +      "confidence_scope": {
        +        "const": "query_to_candidate",
        +        "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +        "type": "string"
        +      },
        +      "cross_street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "cross_street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "intersection_precision": {
        +        "enum": [
        +          "geometric_crossing",
        +          "tangent_intersection",
        +          "centroid_cluster",
        +          "approximate"
        +        ],
        +        "type": "string"
        +      },
        +      "intersection_type": {
        +        "enum": [
        +          "corner",
        +          "interchange"
        +        ],
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "lat": {
        +        "type": "number"
        +      },
        +      "layer": {
        +        "type": "string"
        +      },
        +      "lon": {
        +        "type": "number"
        +      },
        +      "method": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": "string"
        +      },
        +      "place_type": {
        +        "type": "string"
        +      },
        +      "street_kind": {
        +        "enum": [
        +          "street",
        +          "route"
        +        ],
        +        "type": "string"
        +      },
        +      "street_route": {
        +        "maxLength": 128,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedreverse_geocode2 fields changed
      • addedOutput schema / properties / items / items / properties / address_evidence
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "What THIS CANDIDATE carries, component by component — `matched` (a real value is present), `partial` (only a coarser or derived stand-in, e.g. an interpolated house number or a locality falling back to its administrative parent), `absent` (nothing). This describes the result, NOT a comparison against your query: the engine returns no per-component match data, and re-parsing your text here would mean two parsers disagreeing about the same string. Derived from the feature, never from `confidence`.",
        +  "properties": {
        +    "house_number": {
        +      "enum": [
        +        "matched",
        +        "partial",
        +        "absent"
        +      ],
        +      "type": "string"
        +    },
        +    "locality": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    },
        +    "postal_code": {
        +      "description": "Whether the candidate carries a postal code. Presence only — this states what the result has, and makes no claim about its correctness.",
        +      "enum": [
        +        "matched",
        +        "partial",
        +        "absent"
        +      ],
        +      "type": "string"
        +    },
        +    "region": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    },
        +    "street": {
        +      "$ref": "#/properties/items/items/properties/address_evidence/properties/house_number"
        +    }
        +  },
        +  "required": [
        +    "house_number",
        +    "street",
        +    "locality",
        +    "region",
        +    "postal_code"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / items / items / properties / confidence_scope
        Added value: +{
        +  "const": "query_to_candidate",
        +  "description": "What `confidence` is scoped to. `query_to_candidate` means it scores how well this candidate matches the submitted query — it is NOT a probability that the place is real, that the address is correct, or that mail would arrive. Fixed value today; treat it as a closed set that may gain members.",
        +  "type": "string"
        +}
  15. 2 tool updates
    • Changeddirections5 fields changed
      • addedOutput schema / properties / timezone_artifact_version
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / timezone_end / description
        Added value: +"IANA timezone at the route destination, or null when unresolved. Contains information from timezone-boundary-builder, which is made available under the Open Database License (ODbL) v1.0. Timezone boundaries © OpenStreetMap contributors. US legal-zone cross-check: U.S. Department of Transportation, Bureau of Transportation Statistics (public domain)."
      • addedOutput schema / properties / timezone_end_status
        Added value: +{
        +  "enum": [
        +    "resolved",
        +    "boundary_ambiguous",
        +    "source_conflict",
        +    "not_covered",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / timezone_start / description
        Added value: +"IANA timezone at the route origin, or null when unresolved. Contains information from timezone-boundary-builder, which is made available under the Open Database License (ODbL) v1.0. Timezone boundaries © OpenStreetMap contributors. US legal-zone cross-check: U.S. Department of Transportation, Bureau of Transportation Statistics (public domain)."
      • addedOutput schema / properties / timezone_start_status
        Added value: +{
        +  "enum": [
        +    "resolved",
        +    "boundary_ambiguous",
        +    "source_conflict",
        +    "not_covered",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
    • Changedlocate3 fields changed
      • addedOutput schema / properties / timezone / description
        Added value: +"IANA timezone for the point, or null unless timezone_status is resolved. Contains information from timezone-boundary-builder, which is made available under the Open Database License (ODbL) v1.0. Timezone boundaries © OpenStreetMap contributors. US legal-zone cross-check: U.S. Department of Transportation, Bureau of Transportation Statistics (public domain)."
      • addedOutput schema / properties / timezone_artifact_version
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / timezone_status
        Added value: +{
        +  "enum": [
        +    "resolved",
        +    "boundary_ambiguous",
        +    "source_conflict",
        +    "not_covered",
        +    "unavailable"
        +  ],
        +  "type": "string"
        +}
  16. 1 tool update
    • Changedsearch_places2 fields changed
      • changedInput schema / properties / categories / description
        Previous value: -"Structured categories: food, fuel, charging_station, education, health, entertainment, retail, accommodation, nightlife, transport, government, recreation"New value: +"Structured categories: food, fuel, charging_station, education, health, entertainment, retail, accommodation, nightlife, transport, government, recreation. One of `categories` or `query` is required — a bare center (`lat`+`lon`/`center`) with neither is rejected."
      • changedInput schema / properties / query / description
        Previous value: -"Free-text place query such as 'truck stop', 'restaurant', 'charging station'"New value: +"Free-text place query such as 'truck stop', 'restaurant', 'charging station'. One of `query` or `categories` is required — a bare center (`lat`+`lon`/`center`) with neither is rejected."

Publisher details

Operator
ThinAir Telematics, LLC · Publisher source
Operator website
https://geo.thinair.co
Vendor relationship
First-party · Publisher source
Trust center
Not available
Restrictions
Free tier available without a credit card. Paid plans add higher quotas and dedicated API keys. Authentication via OAuth 2.1 (keyless, no custom OAuth app required) or Bearer API key. No admin approval or allowlisting required. Global coverage, no regional restrictions. · Publisher source

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables brand visibility monitoring across major AI platforms like ChatGPT, Claude, Gemini, and Perplexity. It allows users to track visibility scores, analyze competitor data, and receive actionable insights to improve AI-generated brand recommendations.
    16
    24 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Browse IndustryLens's published competitive-intelligence reports and head-to-head competitor comparisons from any AI agent — real, source-backed data.
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources