# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Calling a removed tool by name returns an error naming the tool to use instead, or why none does, rather than `Tool not found`. The error's `details` carry the tool, the last release that listed it and the replacements the client is offered. This covers `tomtom-static-map`, `tomtom-waypoint-routing`, `tomtom-ev-routing`, `tomtom-reachable-range` and `tomtom-get-viz-data`. Removed tools stay out of the tool list, so they cost the model nothing.
- Every call to the TomTom APIs names the AI client in its `TomTom-User-Agent`, after the server's own name and version, e.g. `TomTomMCPSDKHttp/<version> openai-mcp%20(Codex)`. This covers the server's calls and the MCP apps' calls, over HTTP and stdio, so local installs now send the client's name too. The name is the client's `clientInfo.name`, percent-encoded so it stays one token. Over HTTP, a request without an `Mcp-Session-Id`, as ChatGPT sends its tool calls, is named by its raw `User-Agent` instead, e.g. `openai-mcp%2F1.0.0`. The name is `unknown` when neither is usable.

### Changed
- Over HTTP, `client` in the `TomTom-Upstream-Metadata` response header and in the logs follows the same rule: a request without an `Mcp-Session-Id` is named by its raw `User-Agent`, where until now it was `unknown`.
- **BREAKING**: Calling a tool with an input removed in 1.6.12, or with a string where `tomtom-traffic`'s `categoryFilter` or `timeValidityFilter` now takes a list, returns an error that says what changed. The call does not run. Until now the schema stripped an unknown input and ran the call. `details` carries the tool, the last release that had the previous contract (`1.6.11`) and the inputs that triggered it.

### Fixed
- Reading an MCP app whose bundle is missing on the server fails with a JSON-RPC error, the app's URI in its `data`, instead of returning an error page that showed the server's file path.

## [1.6.14] - 2026-10-27

### Changed
- Every data tool keeps its `_meta` in one place, on the result: `show_ui`, and for a result with app data, the tool name and the data under `com.tomtom/app-data`. Until now `show_ui` and the tool name sat in a second `_meta` inside the JSON text. The text carries `show_ui` as a plain field, and the tool name when the result has app data, so a host that drops the result `_meta` can still hide the map.

## [1.6.13] - 2026-10-22

### Removed
- The app-only `tomtom-get-viz-data` tool and the `viz_id` in tool results. The data-viz app calls `tomtom-get-app-data` instead when its data is missing from the result.

### Added
- The HTTP server names the AI client as `client` in the `TomTom-Upstream-Metadata` response header, next to `auth_method`: the `clientInfo.name` the client sent at `initialize`, or `unknown`.
- The app-only `tomtom-report-app-status` tool. Every app reports whether it drew its data, and the server logs it.

### Changed
- **BREAKING** for HTTP servers configured for OAuth (`CIAM_TENANT_ID` and `CIAM_DOMAIN` set): the server refuses to start without `OAUTH_AUDIENCE`. A bearer token must carry the audience of this deployment's Entra resource app; until now an unset `OAUTH_AUDIENCE` only logged a warning and accepted tokens issued for any other TomTom application. Servers that take only API keys need no change.
- The maps-sdk is 1.0.0-rc.2. MapLibre GL JS is 6.13, which that release requires.
- `tomtom-data-viz` reports invalid input as an incorrect-input error, with the offending values (such as the feature count or layer count) under `details` instead of in the error message.
- `tomtom-data-viz` reports an HTTP error from `data_url` by its status: refused access (401, 403), rate limited (429), unavailable (503) or a server error (other 5xx). Any other status, such as a 404 or a redirect, is an incorrect-input error with the status under `details`.
- A TomTom API 403 no longer reads as a bad API key. TomTom answers 401 to a missing or unknown key, and 403 to a valid key that may not call the API: its account has used up its free requests for the API, its plan leaves the API out, or the API is missing from the key's products. The 403 error says the request was refused for the account behind the key, links the pricing page and tells the model that retrying will not help. The 401 error names the key, and where it comes from.

### Fixed
- Maps from the hosted server came up blank about half the time. An app fetched its data from the server instance that ran the tool, and the fetch often reached another instance, which didn't have it. The data now travels inside the tool result, with long route lines simplified to fit the size Claude passes to an app (a 3,300 km route keeps about 9,600 points, within 8 m). A map app without its data, in a host that drops the result's `_meta`, shows an error rather than calling TomTom again. The data-viz app alone runs `tomtom-data-viz` again when its data is missing from the result, which any instance answers. The server keeps no app data, and the result's `_meta` names the `tool`.
- A map whose data can't be loaded shows an error instead of an empty frame.
- `tomtom-traffic` sends its app no data: the app draws live traffic for the bbox and never read the incident list.
- Map apps render again in ChatGPT. Its sandbox allows workers only from `blob:` URLs, and that rule also covers a module worker's imports, so MapLibre's worker could not be started from jsDelivr and every map stayed blank. The worker is now bundled into each app (about 0.5 MB more HTML, 0.15 MB gzipped); MapLibre itself still loads from jsDelivr.

## [1.6.12] - 2026-10-09

### Removed
- **BREAKING**: The `tomtom-reachable-range` tool and its MCP app (`ui://tomtom-routing/reachable-range/app.html`). The Reachable Range API answers 403 to default TomTom API keys, including the keys mcp.tomtom.com issues, so the tool failed for them.
- **BREAKING**: Removed tool inputs that never reached the TomTom API, because neither the maps-sdk nor the service sent them:
  - `tomtom-fuzzy-search`, `tomtom-poi-search`, `tomtom-nearby`: `vehicleTypeSet`, `ext`; `tomtom-nearby` also `parkingAvailability`.
  - `tomtom-geocode`: `timeZone`.
  - `tomtom-reverse-geocode`: `limit`, `countries`, `extendedPostalCodesFor`, `timeZone`, `returnMatchType`, `returnRoadClass`, `callback`, `filter`; and `mapcodes`, `returnSpeedLimit` and `allowFreeformNewLine`, since the maps-sdk reverse geocodes on the Places API v2, which takes none of them.
  - `tomtom-routing`: `alternativeType`, `supportingPoints`, `minDeviationDistance`, `minDeviationTime`, `supportingPointIndexOfOrigin`, `reconstructionMode`, `routeRepresentation`, `extendedRouteRepresentation`, `vehicleHasElectricTollCollectionTransponder`, `arrivalSidePreference`.
  - `tomtom-dynamic-map`: `routeInfoDetail` and `center.label`.
- **BREAKING**: The `TOMTOM_API_BASE_URL` environment variable. Only `tomtom-traffic` read it; every tool now calls the API through the maps-sdk at `https://api.tomtom.com`.
- **BREAKING**: EV route planning, vehicle consumption models and real-time charger availability, which the maps-sdk 1.0 no longer offers:
  - The `tomtom-ev-routing` tool and its MCP app. Charging stops are no longer planned; use `tomtom-routing` for the route and `tomtom-ev-search` for chargers.
  - `tomtom-routing` describes the vehicle with `vehicleMaxSpeed`, `vehicleWeight` and `vehicleHeading` only. `vehicleEngineType`, `currentChargeInkWh`, `maxChargeInkWh`, `constantSpeedConsumptionInkWhPerHundredkm`, `auxiliaryPowerInkW`, `constantSpeedConsumptionInLitersPerHundredkm`, `currentFuelInLiters`, `auxiliaryPowerInLitersPerHour`, `fuelEnergyDensityInMJoulesPerLiter`, `accelerationEfficiency`, `decelerationEfficiency`, `uphillEfficiency`, `downhillEfficiency`, `consumptionInkWhPerkmAltitudeGain` and `recuperationInkWhPerkmAltitudeLoss` are removed, and route summaries no longer carry battery or fuel consumption.
  - `tomtom-ev-search`'s `includeAvailability` and `tomtom-poi-search`'s `chargingAvailability`. Charging stations still list their connectors and power, without their real-time status.

### Changed
- Clients known to render no MCP Apps, such as Claude Code, Gemini CLI, Cline and Zed, no longer get `tomtom-dynamic-map`, `tomtom-data-viz`, the app-only tools (one of which returned the API key), the app resources, or the data tools' `show_ui` and result `_meta`. They drew no map, yet the results read as if they had. Clients that advertise the MCP Apps extension (Claude, ChatGPT, VS Code, Cursor) and any client the server doesn't recognise keep every tool, as some clients render apps without advertising the extension. This works over stdio and HTTP: the stateless HTTP server records the classification in the `Mcp-Session-Id` it returns, which CORS now allows and exposes. A client can choose for itself with `?apps=false` or `?apps=true` on the MCP URL, or `MCP_APPS` over stdio.
- The HTTP server gzips MCP App templates for clients that accept gzip, which cuts a map app from about 0.7 MB to about 0.2 MB on the wire. A `resources/read` is now answered as plain JSON instead of an event stream, which the SDK marks `no-transform`. Other responses stay uncompressed, as tool results can hold a secret next to caller-supplied text.
- An OAuth request that cannot call the TomTom API (`initialize`, `tools/list`, `resources/list`, `resources/read`, `ping`, notifications) no longer exchanges the bearer token for an API key. The token is still verified on every request. A token without access to the API now connects, and fails at its first tool call with the 502 it used to get when connecting. Inside an HTTP request, the server's own `TOMTOM_API_KEY` is never used in place of the request's key.
- The search tools, `tomtom-search-along-route` and `tomtom-routing` share one MCP app, `ui://tomtom-map/places-and-routes/app.html`, in place of ten (`ui://tomtom-search/<tool>/app.html` and `ui://tomtom-routing/route-planner/app.html`, which are gone). A host reads every app's HTML while connecting, one after another, so it now reads 5 apps instead of 14. The app tells results apart by their shape. The EV and area search maps gain the traffic toggles the other maps have, and their POI popups show the place name at the size the other maps use.
- `OAUTH_AUDIENCE` (comma-separated) makes the HTTP server reject bearer tokens issued for any other audience. Unset, the audience is not checked and the server logs a warning at startup.
- Tools reject input combinations the API ignores or refuses, naming the inputs, instead of passing them on:
  - `tomtom-nearby` without `poiCategories` or a brand, fuel, connector or charging-power filter. The Search API returned no results for it.
  - `tomtom-area-search` with more than one area (`center` and `radius`, `polygon`, `boundingBox`), or with `center` or `radius` alone. Only the first area was searched.
  - `tomtom-routing` with both `departAt` and `arriveAt`. `arriveAt` was dropped.
  - `tomtom-geocode`, `tomtom-fuzzy-search` and `tomtom-poi-search` with `radius` but no `position`. The radius was ignored.
  - `tomtom-reverse-geocode` with `entityType` and `heading`, which the API ignores for an `entityType` lookup.
  - `tomtom-geocode`, `tomtom-fuzzy-search` and `tomtom-poi-search` with both `position` and `boundingBox`. The maps-sdk takes one or the other.
  - `tomtom-area-search` with a `polygon` of fewer than 3 points or a `radius` of 0, and `tomtom-routing` with a `vehicleMaxSpeed` or `vehicleWeight` of 0, which the SDK dropped.
  - More than 10 `poiCategories`, `brandSet`, `connectorSet` or `connectorTypes` values, which the Search API refuses.
- `tomtom-routing`'s `sectionType` is described as what it is: a filter on the section types in the response. Compact responses still drop the map-rendering types.
- `tomtom-search-along-route` accepts the `thrilling` `routeType`, like `tomtom-routing`.
- `tomtom-traffic` requires `bbox` in its schema; a call without one always failed.
- `tomtom-data-viz`'s `show_ui` defaults to `true`, as its MCP app already assumed.
- The search tools' `view`, `tomtom-routing`'s `sectionType`, `tomtom-routing`'s and `tomtom-dynamic-map`'s `avoid`, and `tomtom-ev-search`'s `connectorTypes` list their valid values in the tool schema, taken from the maps-sdk. `avoid` now shows `borderCrossings`, `tunnels`, `carTrains` and `lowEmissionZones`, which it accepted but did not list.
- Dropped the unused `jsonwebtoken`, `node-fetch` and `tslib` dependencies.
- The map MCP apps load MapLibre GL JS from jsDelivr (`https://cdn.jsdelivr.net/npm/maplibre-gl@<version>/`, pinned to the installed version) instead of bundling it, which cuts each map app's HTML from about 2.3 MB to about 0.7 MB. The apps' CSP declares `https://cdn.jsdelivr.net` in place of `https://unpkg.com`, so a map app no longer renders where the client cannot reach jsDelivr.
  - The dynamic-map app no longer loads the MapLibre 4 stylesheet from unpkg, which kept the maps-sdk from applying the stylesheet of the MapLibre it runs.
- The maps-sdk is 1.0.0-rc.1 (was 0.51):
  - **BREAKING**: `tomtom-fuzzy-search`, `tomtom-poi-search`, `tomtom-nearby` and `tomtom-geocode` page with `cursor` instead of `ofs`: pass the `nextCursor` of the previous response, which compact responses now keep. `tomtom-ev-search` takes `cursor` too.
  - **BREAKING**: `poiCategories` takes the maps-sdk's current category codes, which `tomtom-poi-categories` returns. 75 codes changed, such as `GAS_STATION` (now `FUEL_STATION`), `ELECTRIC_VEHICLE_STATION` (`CHARGING_LOCATION`) and `SUPERMARKETS_HYPERMARKETS` (`SUPERMARKET`); an old code is rejected, naming it.
  - **BREAKING**: `tomtom-reverse-geocode` answers from the Places API v2. Addresses no longer carry `buildingNumber`, `street`, `streetNameAndNumber`, `routeNumbers` or `localName`, `neighbourhood` is `neighborhood`, and a position with no address nearby returns a feature without `properties`.
  - `tomtom-traffic` calls Traffic Incident Details v2. Its `full` incidents no longer carry `tmc`.
  - `tomtom-poi-categories` returns each keyword's best-matching categories, ignoring accents: `bar` finds Bar, not the 15 categories whose names contain it.
  - Every EV place now lists its charging points under `chargingPark.chargingStations`. Compact responses drop the list, as the connectors summarise it.
- **BREAKING**: `tomtom-traffic` calls the Traffic API through the maps-sdk, like the other tools:
  - `categoryFilter` takes a list of names (`accident`, `jam`, `road-closed`, `roadworks`, …) instead of comma-separated codes, and `timeValidityFilter` a list (`["present", "future"]`) instead of a comma-separated string.
  - `fields` is removed. The SDK always requests the fields that were its default; the only other field, `aci`, is always empty.
  - Incidents carry the SDK's names: compact responses have `category` and `magnitudeOfDelay` names (`road-closed`, `major`) and `lengthInMeters` and `delayInSeconds`, instead of `iconCategory` and `magnitudeOfDelay` codes and `length` and `delay`. `incidentSummary.incidentsByCategory` replaces `incidentsByIconCategory`. `full` returns a GeoJSON FeatureCollection instead of an `incidents` list.
  - `maxResults` still caps the incidents returned, but is no longer sent to the API, which ignored it.

### Fixed
- Tool inputs that were accepted but never sent now reach the TomTom API:
  - `tomtom-ev-search` applies `minPowerKW` across all stations in range. It filtered only the first page, so where the nearest chargers were slow it returned none.
  - `tomtom-fuzzy-search`, `tomtom-poi-search`, `tomtom-nearby`: `minPowerKW`, `maxPowerKW`, `brandSet`, `connectorSet`, `fuelSet`, `view`; fuzzy search also `entityTypeSet`, `idxSet`; POI search also `boundingBox` and `typeahead`.
  - `tomtom-geocode`: `radius`, `view`, `entityTypeSet`.
  - `tomtom-reverse-geocode`: `heading`, `entityType`, `view`.
  - `tomtom-routing`: every vehicle input (`vehicleMaxSpeed`, `vehicleWeight`, `vehicleHeading`) and `sectionType`.
- `tomtom-traffic`'s `categoryFilter` described the category codes wrongly (`0` as accidents, `8` as road works), so it returned other incidents than asked for. It now takes category names.
- `tomtom-dynamic-map` uses a `center` given without `zoom`, zooming to keep the content in view around it, and a `zoom` given without `center`; it ignored each unless both were set. It draws `routes` alongside `routePlans`, where it dropped them, and keeps a polygon `strokeWidth` of 0, which it drew as 2.
- TomTom API errors map to the key, rate-limit and server-error messages again for every tool. Errors from the maps-sdk other than a 403 ended as unknown errors, and `tomtom-data-viz` reported a failing `data_url` as a TomTom API key or server problem.
- Tool descriptions that stated wrong defaults: the search tools' `limit` (10, not 5; `tomtom-nearby` 20), and `tomtom-ev-search`'s `radius` (no default; without it there is no distance limit).

## [1.6.11] - 2026-10-05

### Added
- `response_detail: "geometry"` on `tomtom-routing`, `tomtom-ev-routing`, `tomtom-reachable-range`, `tomtom-traffic`, `tomtom-area-search` and `tomtom-search-along-route`. It returns the compact response plus a GeoJSON FeatureCollection of the route lines, areas or incidents, capped at 1,000 vertices per feature. The design is in [docs/adr/](docs/adr/README.md), ADRs 0001 to 0007.

### Removed
- **BREAKING**: Dropped the second ("Genesis") maps backend. All tools now run on the TomTom Orbis Maps APIs, which were the HTTP server's default; the stdio server used Genesis unless `MAPS=tomtom-orbis-maps` was set.
  - The `MAPS` environment variable and the `tomtom-maps-backend` HTTP header are no longer read. The header is also no longer in the CORS allow-list, so browser clients that still send it fail preflight.
  - The `tomtom-static-map` tool is gone; the Orbis APIs have no static-map endpoint. Use `tomtom-dynamic-map`.
  - The `tomtom-waypoint-routing` tool is gone. Use `tomtom-routing`, whose `locations` takes the origin, any stops and the destination.
  - Clients that ran on Genesis now get the Orbis tool schemas: search tools take `position` ([lon, lat]), `countries`, `boundingBox` and `poiCategories` instead of `lat`/`lon`, `countrySet`, `topLeft`/`btmRight` and `categorySet`; `tomtom-routing` takes `locations` instead of `origin`/`destination`; the truck parameters (`vehicleWidth`, `vehicleHeight`, `vehicleLoadType` and the like) are gone. They also gain `tomtom-area-search`, `tomtom-ev-search`, `tomtom-search-along-route`, `tomtom-poi-categories`, `tomtom-ev-routing` and `tomtom-data-viz`.
  - `tomtom-dynamic-map`'s `routePlans[].routeType` now takes `fast`/`short`/`efficient`/`thrilling` (was `fastest`/`shortest`/`eco`/`thrilling`), and `travelMode` accepts only `car` — matching `tomtom-routing`.
- **BREAKING**: `tomtom-dynamic-map` no longer renders a server-side image. The map is drawn by its MCP app, so the visual needs a client that supports MCP apps; other clients get a JSON summary of its view, markers, routes and areas. The `detail` parameter is removed, `show_ui` now defaults to `true`, and `width`/`height` are no longer capped at 800×600 (the schema allows up to 2048).

### Changed
- Dropped the `Orbis` qualifier from file names, types and log messages now that there is only one backend. This is internal only; tool names, tool schemas and MCP app resource URIs are unchanged.
- The MCP server now always reports its name as `TomTom Maps MCP Server`.
- **BREAKING**: `tomtom-reachable-range` computes only the requested budget, with one API call instead of up to four. The response holds one range, and the top-level `requestedBudgetValue` is gone. The MCP app's Range selector fetches the other budgets (0.5×–2×) when you pick them.
- Compact responses, the default, are about 37% smaller: they drop output that carries no information and add back fields that answer common questions.
- Tool descriptions promise only what each tool returns, name the geometry that compact responses leave out, and no longer send agents to `tomtom-dynamic-map` from the data tools.
- `tomtom-reachable-range` rejects the efficiency inputs without `vehicleWeight`, naming it. The API refuses that combination; it only seemed to work while the inputs were dropped.
- Every outbound call the HTTP server makes to authenticate a request has a deadline, so a silent upstream fails the request instead of leaving it open.
- The maps-sdk is 0.51.3 and the MCP apps run on MapLibre GL JS 6.

### Fixed
- `tomtom-reachable-range` returned the caller's TomTom API key in `full` responses and in the data its MCP app reads.
- `tomtom-ev-search` with `minPowerKW` dropped every charging station that had connector data.
- `tomtom-geocode`'s `countries` and `tomtom-reverse-geocode`'s `radius` now reach the TomTom API.
- `tomtom-reachable-range`'s `vehicleMaxSpeed`, `vehicleWeight` and efficiency inputs now reach the TomTom API.
- Clicking a place marker in the search apps opens its popup again.
- `tomtom-traffic` now honours its `fields` parameter.
- `tomtom-dynamic-map` accepts a map framed by `bbox` alone, and draws route labels when `showLabels` is set.

Versions 1.1.1 to 1.6.10 have no entry here; see the [GitHub releases](https://github.com/tomtom-international/tomtom-maps-mcp/releases) for them.

## [1.1.0] - 2025-09-18

### Added
- Added support for TomTom Orbis Maps
- New tool added `dynamic-map-tool` allows to add markers, routes and polygons on map

## [1.0.0] - 2025-06-30

### Added
- Initial open source release of TomTom MCP Server
