by tomtom-international
Provides TomTom's geolocation, search, routing, and traffic capabilities to AI agents through the Model Context Protocol, enabling precise map‑based interactions in AI workflows.
The server exposes TomTom’s location‑based APIs—geocoding, POI search, routing, traffic incidents, and dynamic map visualisation—as Model Context Protocol tools. AI agents can call these tools to obtain coordinates, routes, traffic information, or render interactive maps directly within their environment.
npx @tomtom-org/tomtom-mcp@latest
The server starts in stdio mode for AI assistants or in HTTP mode on port 3000 when built.http://localhost:3000/mcp or the public preview https://mcp.tomtom.com/maps) and include the header tomtom-api-key: <YOUR_API_KEY>.{
"method": "tools/call",
"params": { "name": "tomtom-geocode", "arguments": { "query": "Amsterdam Central Station" } },
"jsonrpc": "2.0",
"id": 1
}
pnpm run ui to explore tools and see interactive maps.compact, geometry, or full to balance token usage vs. data richness.Q: Do I need to install Node.js locally? A: Only Node 22.x (or a later version) is required. The server can also run as a Docker container.
Q: Can I use the remote preview server instead of running locally?
A: Yes. Point your client to https://mcp.tomtom.com/maps and supply the tomtom-api-key header.
Q: Which environment variable holds the API key?
A: Set TOMTOM_API_KEY (or place it in a .env file). The server reads this variable at startup.
Q: How do I get full geometry data for routes?
A: Include response_detail: "geometry" (or "full") in the tool arguments.
Q: My API calls return 403 errors. What should I do? A: Ensure your API key has the TomTom Orbis Maps products enabled. If the preview is not available for your account, request access via the developer portal.
Q: Is there a way to run the server without Docker?
A: Yes, using npx @tomtom-org/tomtom-mcp@latest for stdio mode or building with pnpm run build and starting node bin/tomtom-mcp-http.js for HTTP mode.
The TomTom Maps MCP Server simplifies geospatial development by providing seamless access to TomTom’s location services, including search, routing, traffic and interactive maps. It enables easy integration of precise and accurate geolocation data into AI workflows and development environments.

Public Preview — The TomTom Maps Remote MCP Server is currently in public preview.
The easiest way to get started is to connect directly to TomTom's hosted MCP Server — no Node.js, Docker, or local setup needed.
Endpoint:
https://mcp.tomtom.com/maps
Prerequisites:
Add the following to your MCP client configuration:
{
"mcpServers": {
"tomtom-mcp": {
"type": "http",
"url": "https://mcp.tomtom.com/maps",
"headers": {
"tomtom-api-key": "your_api_key_here"
}
}
}
}
Create or edit .vscode/mcp.json in your workspace:
{
"servers": {
"tomtom-mcp": {
"type": "http",
"url": "https://mcp.tomtom.com/maps",
"headers": {
"tomtom-api-key": "your_api_key_here"
}
}
}
}
The quickest option is to install the pre-built extension — see the Claude Desktop Setup guide for details.
Alternatively, configure Claude Desktop to use the remote server directly by editing your configuration file:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json{
"mcpServers": {
"tomtom-mcp": {
"type": "http",
"url": "https://mcp.tomtom.com/maps",
"headers": {
"tomtom-api-key": "your_api_key_here"
}
}
}
}
Note: If your MCP client does not support remote HTTP connections with custom headers, use the local setup instead.
Keeping local deployments of the TomTom Maps MCP Server up-to-date is the responsibility of the MCP client/operator. TomTom publishes updates to address known vulnerabilities, but failing to apply updates, patches, or recommended security configurations to your local instance may expose it to known vulnerabilities.
How to obtain a TomTom API key:
For more details, visit the TomTom API Key Management Documentation.
npm install @tomtom-org/tomtom-mcp@latest
# or run directly without installing
npx @tomtom-org/tomtom-mcp@latest
Set your TomTom API key using one of the following methods:
# Option 1: Use a .env file (recommended)
echo "TOMTOM_API_KEY=your_api_key" > .env
# Option 2: Environment variable
export TOMTOM_API_KEY=your_api_key
# Option 3: Pass as CLI argument
TOMTOM_API_KEY=your_api_key npx @tomtom-org/tomtom-mcp@latest
| Variable | Description | Default |
|---|---|---|
TOMTOM_API_KEY |
Your TomTom API key | - |
PORT |
Port for the HTTP server | 3000 |
LOG_LEVEL |
Logging level: debug, info, warn, or error. Use debug for local development to see all logs |
info |
MCP_APPS |
Stdio only. false gives the client only the data tools, without maps; true gives every tool. Unset, the client's initialize decides. Over HTTP, use ?apps= on the MCP URL (see Clients without MCP apps) |
- |
Stdio Mode (Default - for AI assistants like Claude):
# Start MCP server via stdio
npx @tomtom-org/tomtom-mcp@latest
HTTP Mode (for web applications and API integration):
pnpm run build # Build first (required)
pnpm run start:http
# or run the built binary directly
node bin/tomtom-mcp-http.js
When running in HTTP mode, you need to include your API key in the tomtom-api-key header:
tomtom-api-key: <API_KEY>
For example, to make a request using curl:
curl --location 'http://localhost:3000/mcp' \
--header 'Accept: application/json,text/event-stream' \
--header 'tomtom-api-key: <API KEY>' \
--header 'Content-Type: application/json' \
--data '{
"method": "tools/call",
"params": {
"name": "tomtom-geocode",
"arguments": {
"query": "Amsterdam Central Station"
}
},
"jsonrpc": "2.0",
"id": 24
}'
The Docker setup is also configured to use this HTTP mode with the same authentication method.
Docker Mode (recommended):
# Option 1: Using docker run directly
docker run -p 3000:3000 ghcr.io/tomtom-international/tomtom-maps-mcp:latest
# Option 2: Using Docker Compose (recommended for development)
# Clone the repository first
git clone https://github.com/tomtom-international/tomtom-maps-mcp.git
cd tomtom-maps-mcp
# Start the service
docker compose up
Both Docker options run the server in HTTP mode. Pass your API key via the tomtom-api-key header as shown in the HTTP Mode curl example above.
TomTom Maps MCP Server can be easily integrated into various AI development environments and tools.
These guides help you integrate the MCP server with your tools and environments:
The dynamic map tool renders nothing server-side. It resolves the request into map state — the basemap style to load, the viewport to open on, and GeoJSON sources and layers for the markers, routes and polygons requested — calculating any routePlans through the Routing API along the way.
That state is cached and the tool returns its viz_id. The MCP app fetches it with the app-only tomtom-get-viz-data tool and draws the map client-side, so panning, zooming and clicking work on a live map.
Because the map is drawn by the app, the visual requires an MCP client that supports MCP apps. A client the server knows renders no MCP apps, such as Claude Code, Gemini CLI, Cline or Zed, does not get tomtom-dynamic-map, tomtom-data-viz, the app-only tools or show_ui at all (see Clients without MCP apps). Any other client without MCP apps receives a JSON summary of what the map shows: its view, markers, routes (distance, travel time, traffic delay) and areas.
When a client connects, its initialize request decides what it gets, over stdio and HTTP alike:
| The client | Gets |
|---|---|
advertises the MCP Apps extension (io.modelcontextprotocol/ui with text/html;profile=mcp-app): Claude (web, desktop, mobile), ChatGPT, VS Code, Cursor, Goose Desktop |
every tool, with maps |
is known to render no MCP apps, by its clientInfo.name: Claude Code, Gemini CLI, Cline, Zed, Goose CLI, Continue, Amazon Q CLI, opencode, Roo Code |
the data tools only, without show_ui, app resources or the _meta the apps read |
| neither | every tool, as before: some clients render apps without advertising the extension |
The HTTP server keeps no state, so its initialize response returns an Mcp-Session-Id of the form <apps>.<client>.<uuid> recording this classification and the client's family (claude-ai, claude-code, chatgpt, codex, other or unknown, from its clientInfo.name), and the client sends it with every later request. The family is also reported as client in the TomTom-Upstream-Metadata response header, next to auth_method, for the gateway's analytics.
A client can also choose for itself, which is useful for a headless agent or a client in the last row. Over HTTP, add ?apps=false to the MCP URL (for example https://mcp.tomtom.com/maps?apps=false) for the data tools only, or ?apps=true for every tool. Over stdio, set MCP_APPS=false or MCP_APPS=true in the server's environment.
The map apps load MapLibre GL JS from https://cdn.jsdelivr.net rather than bundling it, so the client must be able to reach jsDelivr as well as api.tomtom.com. Both are declared in the apps' content security policy. MapLibre's worker is bundled into each app instead, because ChatGPT's sandbox allows workers only from blob: URLs.
References:
Every tool that returns TomTom data accepts a response_detail parameter (all but tomtom-poi-categories, tomtom-dynamic-map and tomtom-data-viz). The four tools that return geometry (tomtom-routing, tomtom-traffic, tomtom-area-search and tomtom-search-along-route) accept three values; the others accept compact and full.
| Value | Returns |
|---|---|
compact (default) |
Essential fields and the point coordinates of a place. No geometry: route lines, traffic incident locations and search areas are omitted. |
geometry |
compact, plus a geometry key holding that geometry as a GeoJSON FeatureCollection. |
full |
The raw API response: lossless, in the API's own shape, and many times larger. |
The default is tuned for conversational use, where a route line would consume most of a model's context for no benefit. If you are building on top of the server and need the coordinates themselves, to draw the result on your own map or run your own analysis, request response_detail: "geometry". Use full only when you need fields that compact drops, or the exact line.
For an Amsterdam-to-Berlin route, geometry is about 22 KB: the 8,000-point line is simplified to 1,000 vertices, at most 13 m from the original. full is about 210 KB.
geometry FeatureCollection{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { "summary": { "lengthInMeters": 663425, "travelTimeInSeconds": 24453 } }
}
],
"geometry": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": { "type": "LineString", "coordinates": [[4.90413, 52.36761], [4.90419, 52.36755]] },
"properties": {
"route": 0,
"simplification": { "original_points": 8151, "points": 1000, "max_error_m": 13 }
}
}
]
}
}
Coordinates follow RFC 7946: [longitude, latitude], rounded to 5 decimal places (about 1.1 m). Polygon rings are closed.
One feature per item. Its properties hold only a join key giving the item's position in the rest of the response. A join key is valid within one response only; don't store it as an identifier.
| Tool | Features | properties |
|---|---|---|
| Routing | One LineString per route |
{"route": 0} |
| Traffic | One Point or LineString per incident, as the API returns it |
{"incident": 12}, matching incidents[12] |
| Area search | The search boundary Polygon |
{"boundary": "circle"}, "polygon" or "boundingBox" |
| Search along route | The route LineString |
{"route": 0} |
At most 1,000 vertices per feature. Longer lines are simplified, and the feature then carries simplification: the original and returned vertex counts, and max_error_m, an upper bound in whole metres on the distance between a dropped vertex and the returned line, including the shift from rounding coordinates to 5 decimals. A long route is accurate at the zoom that shows all of it, but visibly approximate when zoomed in; if max_error_m is too large for your use, request full. A polygon that would cross itself after simplification keeps more vertices instead, so it can exceed 1,000.
No vertex indexes. Route sections and legs point into the API's original line, which a simplified line no longer matches, so geometry responses drop startPointIndex, endPointIndex and pointIndex.
The design is recorded in docs/adr/.
Note: Hosts that support MCP Apps render the interactive map widget from the untrimmed response regardless of this setting, so
compactloses nothing visually. Theshow_uiparameter requests that widget and is ignored by hosts that cannot render it; it is not a way to obtain coordinates. Clients known to render no MCP apps don't get the parameter.
A built-in debug UI lets you visually test MCP tools and their interactive map widgets without needing an AI client.
pnpm run ui
This starts both the MCP HTTP server (port 3000) and the debug UI host (port 8080). Open http://localhost:8080 in your browser.
show_ui: true for map widgets)Cmd+Enter to run, Cmd+K to search toolspnpm run ui)TOMTOM_API_KEY in your .env fileThe UI host is a workspace package (tomtom-mcp-app-host in ui/), so the root pnpm install already installed its dependencies.
pnpm run ui:build # Build the UI
pnpm --filter tomtom-mcp-app-host start # Start only the UI host (assumes MCP server is already running)
This project uses pnpm (
>=11) as its package manager. Install it withnpm install -g pnpmorcorepack enable. Linting and formatting are handled by Biome.
git clone https://github.com/tomtom-international/tomtom-maps-mcp.git
cd tomtom-maps-mcp
pnpm install
cp .env.example .env # Add your API key in .env
pnpm run build # Build TypeScript files
node ./bin/tomtom-mcp.js # Start the MCP server
pnpm run build # Build TypeScript
pnpm test # Run all tests
pnpm run test:all # All tests (unit + stdio + http)
⚠️ Important: The tests require a valid API key in .env: the service and tool tests make real API calls, which consume your API quota.
pnpm run test:e2e:oauth connects to the deployed MCP server with the MCP SDK client, the library the connectors are built on, and follows the same path a connector does: the server's 401 names the authorization server, the SDK discovers it and opens the authorize request, a browser picks the sign-in tenant and logs the test user in, the SDK redeems the code, and the session calls a tool with the token. It runs for every account and connector of a target, with the same connectors on both targets, so a change on dev is checked the way real users will meet it on prod.
| Target | MCP server | Authorization server it must advertise | Connectors | Last step |
|---|---|---|---|---|
prod (default) |
mcp.tomtom.com/maps |
oauth.my.tomtom.com |
ChatGPT, Claude | geocode returns a result |
dev |
mcp-dev.api-system.tomtom.com/maps |
staging.oauth.my.tomtom.com |
ChatGPT, Claude | geocode returns a key rejection |
local |
localhost:3000/mcp, started by you |
staging.oauth.my.tomtom.com |
the test client dev serves | geocode returns a key rejection |
The authorization server is discovered from the MCP server, never configured in the test; the test only asserts that the discovered one is the expected one, so a deployment pointing at the wrong ULS instance fails in the first step with that message. The connectors are the registered redirect URIs of ChatGPT and Claude; the sign-in tenant is chosen on the ULS page the way a user does, with no tenant shortcut.
On dev the last step proves the key exchange and not the tool result: most API services behind ULS staging are not fully functional, so the geocode call comes back with a key rejection, and that rejection is what the test asserts.
Select the target with OAUTH_E2E_TARGET. Accounts come from the environment, .env locally. A missing pair skips that account locally and fails the run in CI, so a misconfigured secret can never pass.
E2E_B2B_EMAIL, E2E_B2B_PASSWORD: workforce user, prod only. The workforce tenant holds no resource app for the dev origin yet, so that login cannot succeed on dev.E2E_B2C_PROD_EMAIL, E2E_B2C_PROD_PASSWORD: external user on prod.E2E_B2C_DEV_EMAIL, E2E_B2C_DEV_PASSWORD: external user on dev and local.On prod and dev the test needs no server running and starts none. The browser resolves the connectors' redirect hosts to 127.0.0.1, so a captured authorization code never reaches a third party.
local checks the OAuth path of a build on this machine without a dev deployment. Start the server with the env block of the dev deployment in tomtom-mcp-infra (.kaap/helm/dev/app.yaml), leaving out MCP_BASE_URL and MCP_BASE_URL_PATH so it advertises itself as localhost, then run the test against it:
AUTHORIZATION_SERVER_URL=... ULS_TOKEN_ENDPOINT=... ULS_CLIENT_ID=... CIAM_TENANT_ID=... CIAM_DOMAIN=... WORKFORCE_TENANT_ID=... pnpm run dev:http
OAUTH_E2E_TARGET=local pnpm run test:e2e:oauth
ChatGPT and Claude cannot reach a local server, so local logs in through the test client that dev serves at /maps/inspector-client.json, registered on ULS staging with a loopback redirect. That is why local depends on dev being up, and why the workforce account is left out: the dev origin has no workforce resource app.
The OAuth end-to-end workflow runs it in CI and posts to Slack only when the outcome changes:
prod;tomtom-mcp-infra, after waiting for the rollout;src/
├── apps/ # MCP App UI resources
├── handlers/ # Request handlers
├── schemas/ # Validation schemas
├── services/ # TomTom API wrappers
├── tools/ # MCP tool definitions
├── types/ # TypeScript type definitions
├── utils/ # Utilities
├── createServer.ts # MCP Server creation logic
├── index.ts # Main entry point (stdio)
└── indexHttp.ts # HTTP server entry point
echo $TOMTOM_API_KEY # Check if set
ls -la .env # Verify .env exists
cat .env # Check API key
pnpm run build # Rebuild
pnpm store prune # Clear cache
If you see an error stating "missing permissions", it means your API key does not have access to the TomTom Orbis Maps services, which back all of this server's tools.
Note: TomTom Orbis Maps are currently in Public Preview. They may not be available on all developer accounts by default.
How to troubleshoot:
We welcome contributions to the TomTom Maps MCP Server! Please see CONTRIBUTING.md for details on how to submit pull requests, report issues, and suggest improvements.
All contributions must adhere to our Code of Conduct and be signed-off according to the Developer Certificate of Origin (DCO).
Open issues on the GitHub repo
Please see our Security Policy for information on reporting security vulnerabilities and our security practices.
This project is licensed under the Apache License 2.0 - see the LICENSE.md file for details.
Copyright (C) 2025 TomTom Navigation B.V.
Please log in to share your review and rating for this MCP.
Explore related MCPs that share similar capabilities and solve comparable challenges
by exa-labs
Provides real-time web search capabilities to AI assistants via a Model Context Protocol server, enabling safe and controlled access to the Exa AI Search API.
by perplexityai
Enables Claude and other MCP‑compatible applications to perform real‑time web searches through the Perplexity (Sonar) API without leaving the MCP ecosystem.
by Aas-ee
Provides multi-engine web search and article/content retrieval through an MCP server, command‑line interface, and a reusable local daemon, all without requiring API keys or authentication.
by MicrosoftDocs
Provides semantic search and fetch capabilities for Microsoft official documentation, returning content in markdown format via a lightweight streamable HTTP transport for AI agents and development tools.
by elastic
Enables natural‑language interaction with Elasticsearch indices via the Model Context Protocol, exposing tools for listing indices, fetching mappings, performing searches, running ES|QL queries, and retrieving shard information.
by graphlit
Enables integration between MCP clients and the Graphlit platform, providing ingestion, extraction, retrieval, and RAG capabilities across a wide range of data sources and connectors.
by ihor-sokoliuk
Provides web search capabilities via the SearXNG API, exposing them through an MCP server for seamless integration with AI agents and tools.
by mamertofabian
Fast cross‑platform file searching leveraging the Everything SDK on Windows, Spotlight on macOS, and locate/plocate on Linux.
by spences10
Provides unified access to multiple search engines, AI response tools, and content processing services through a single Model Context Protocol server.
{
"mcpServers": {
"tomtom-mcp": {
"command": "npx",
"args": [
"-y",
"@tomtom-org/tomtom-mcp@latest"
],
"env": {
"API_KEY": "<YOUR_API_KEY>"
}
}
}
}claude mcp add tomtom-mcp npx -y @tomtom-org/tomtom-mcp@latest