komoot-mcp
# komoot-mcp
An MCP server that lets Claude search your Komoot tours by distance, start point, surface and scenery, and build new gravel routes from the best sections of tours you already saved.
## Preview
```text
You: Find me a 50 km gravel loop within 30 minutes of Amsterdam,
at least 60% unpaved, and tell me what is scenic along the way.
Claude: I checked 14 planned tours near Amsterdam and pulled surface data for the
closest matches.
1. Vechtplassen gravel loop: 48 km, 71% gravel (compacted and dirt),
starts in Weesp (25 min drive). Passes 3 saved highlights:
Ankeveense Plassen, Fort Uitermeer, Naardermeer boardwalk.
2. Diemerbos and IJmeer dike: 52 km, 63% gravel, starts at Diemen.
Exposed dike section for 9 km, watch the wind.
3. Spaarnwoude polders: 55 km, 58% gravel, just under your target.
Want the GPX for route 1, or should I build a new loop that combines
the gravel sections of all three?
```
## What it does
```mermaid
%%{init: {"flowchart": {"wrappingWidth": 600, "nodeSpacing": 30, "rankSpacing": 32}}}%%
flowchart TB
Q(["You, in Claude: a distance, a start, how much gravel, what to see"]):::human
Q --> CL["`**Claude** picks the tools and calls them over MCP`"]:::sys
CL --> T1["list_tours: planned and recorded, by sport, place, radius"]:::sys
T1 --> T2["get_tour_segments: surface and way-type spans turned into percentages"]:::sys
T2 --> T3["get_highlights and your saved ones, near a point"]:::sys
T3 --> RC["build_combined_route: single-surface segments, forward runs, scored by gravel and highlights"]:::sys
RC --> OS["OSRM public cycling router joins the chosen runs"]:::sys
OS --> OUT["A GPX track plus a waypoint list for the Komoot planner"]:::out
OUT --> R(["You ride it, or upload it as a new planned tour"]):::human
classDef sys fill:#1f3a5f,stroke:#7aa2d8,color:#ffffff
classDef human fill:#6b4514,stroke:#e0a95a,color:#ffffff
classDef out fill:#1e4d3a,stroke:#6fcf97,color:#ffffff
```
1. Lists your planned and recorded tours by sport, location and radius.
2. Returns a tour's surface breakdown (gravel, asphalt, dirt) and way types, so a ride can be scored by how much is unpaved.
3. Downloads any tour as GPX, or uploads a GPX as a new planned tour.
4. Finds highlights near a point, and reads the ones you bookmarked.
5. Builds a new route from the gravel sections of several saved tours, joined by short OSRM cycling connectors, as a GPX track plus a waypoint list for the Komoot planner.
**Constraints:** credentials live in the system keychain or in environment variables, never on disk in this project. Tests run without network.
## Why this exists
I ride gravel around Amsterdam and wanted to plan rides from inside Claude instead of clicking through maps. Komoot has the surface data; this server makes it available as tools, and [gravel-ride-plan](https://github.com/nunomnferreirapt/gravel-ride-plan) uses them for the route step of a full ride plan. It is the same habit as the work tools on my profile: when a routine has a data source, give the assistant the tools and let it do the lookups.
## Requirements
- Python 3.10 or newer and [uv](https://docs.astral.sh/uv/)
- A Komoot account. Credentials go in environment variables or the system keychain (see Install); they are never written to disk by this project.
- Claude Code or Claude Desktop
Unofficial: this server talks to Komoot's web API and is not affiliated with or endorsed by Komoot; use it within Komoot's terms, at your own risk. The route combiner calls the public OSRM demo server, at most 30 calls per build, within its light-use policy.
## Install
```bash
git clone https://github.com/nunomnferreirapt/komoot-mcp.git
cd komoot-mcp
uv sync
uv run pytest
```
Register the server, then ask Claude once to run the `setup_credentials` tool: it stores your Komoot email and password in the system keychain under the service `komoot-mcp`, and no config file ever holds them. The password passes through the conversation that one time; set the two environment variables instead if you would rather it never did. Claude Code:
```bash
claude mcp add -s user komoot-mcp -- uv --directory /absolute/path/to/komoot-mcp run komoot-mcp
```
Claude Desktop, in `claude_desktop_config.json`:
```json
{
"mcpServers": {
"komoot-mcp": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/komoot-mcp", "run", "komoot-mcp"]
}
}
}
```
If you prefer environment variables, set `KOMOOT_EMAIL` and `KOMOOT_PASSWORD` in the server's `env` block instead; they take precedence over the keychain. That block sits in plain text in the client's config file (`claude_desktop_config.json`, or `~/.claude.json` for Claude Code), so the keychain is the safer place; to keep the password out of the config, export the two variables in the shell that starts the client.
Optional variables: `KOMOOT_MCP_ROUTES_DIR` (where built routes are saved, default `~/komoot-mcp-routes`) and `KOMOOT_MCP_CACHE_DIR` (parsed tour cache, default `~/.cache/komoot-mcp`). Both hold your tours' full GPS tracks and your saved highlights in plain files, so keep them outside any folder you push to a public repo.
## Usage
Ask in plain language: "list my planned tours near Utrecht", "how much of tour 123456 is gravel", "build a 60 km gravel loop from Weesp using my saved tours". The tools are `list_tours`, `get_tour_details`, `get_tour_segments`, `download_tour_gpx`, `upload_gpx_to_komoot`, `get_highlights`, `get_saved_highlights`, `build_combined_route` and `setup_credentials`. To run the server by hand: `uv run komoot-mcp` (it speaks MCP over stdio).
## How the route combiner works
A FastMCP app over Komoot's web API. It signs in with Basic Auth, keeps the short-lived session token in memory and retries once on a 401. Tour responses carry surface and way-type spans indexed into the coordinate array; the client turns these into percentages. The route combiner splits each tour into single-surface segments, groups them into runs that move forward along the start-to-end corridor, scores runs by gravel length and nearby saved highlights, and joins the chosen runs with OSRM's public cycling router. Parsed segments are cached on disk, so a rebuild only fetches tours it has not seen.
## Repository layout
```text
src/komoot_mcp/
__main__.py MCP tools and server entry point
auth.py credentials and Basic Auth session
client.py Komoot API calls and surface parsing
route_combiner.py segment splitting, run selection, OSRM connectors, GPX output
cache.py disk cache for parsed segments and highlights
tests/ pytest, no network
pyproject.toml uv project, console script komoot-mcp
```
## License
MIT, see `LICENSE`.
Built by [Nuno Ferreira](https://www.linkedin.com/in/nunomnferreira).
TDQS
Scored across 9 tools
Each tool has a largely distinct purpose, and the descriptions clarify potential overlaps. The main possible confusion is between get_tour_details and get_tour_segments, but the text explicitly differentiates aggregated data from raw segment arrays. Highlight tools are also distinguished by location-based versus saved/bookmarked results.
All tool names follow a clear snake_case, verb-first action_object pattern (e.g., setup_credentials, list_tours, download_tour_gpx, build_combined_route). The convention is consistent across the entire set with no mixed casing or vague verb styles.
Nine tools is well-scoped for a Komoot integration focused on credential setup, tour browsing, GPX handling, highlights, and route building. Each tool serves a distinct step in these workflows, with no obviously redundant or missing count-level concerns.
The surface covers credentials, tour listing/details, raw segments, GPX download/upload, highlights, saved highlights, and combined route building, forming a coherent gravel-planning toolkit. Minor gaps exist around tour metadata update/delete and saving highlights, but core creation/read/export/route-building workflows are covered.