flow-planner
Exports planned cycling routes as GPX files with elevation, ready for import into Garmin Connect.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@flow-planner Plan a 60 km climbing loop from Rathfarnham."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
bike-mapper
A road-cycling route planner for Dublin and Wicklow that ranks routes by how often you will have to stop, not just by how far you ride. It plans loops, out-and-backs and one-way rides to a target length, can seek out the hardest climbs or avoid them, keeps you off main roads if you ask, and exports GPX files that import straight into Garmin Connect. It runs as a local web page and as an MCP server, so you can plan a ride by talking to Claude Code.
Everything is built on open data: OpenStreetMap, the Copernicus GLO-30 elevation model and BRouter. The project started as a feasibility study (see Research) into whether open data can predict where a cyclist stops; the planner is what came out of it.
What it does
Fewest-stops routing. Every candidate route is scored against a directional index of stop causes derived from OSM (traffic signals, stop and give-way signs, roundabout entries, junction priority) and a per-class stop model, giving expected stops, stops per km and expected stopped time.
Three ride shapes with a length target.
loop,out_and_back(same road back, or a free return) andone_way, withlength_kmor an explicitmin_km/max_kmrange. Loops are searched over ring and petal via-point shapes so they still close from awkward starts such as the Howth peninsula.Three objectives.
flow(fewest stops and turns),climb(most and hardest climbing, via-points picked from the DEM) andflat.Tunable routing. Lane bonus, turn cost, lane-exit cost, cycleway weight and a
main_road_penalty(1 to 5) that trades distance for quieter roads, with presets (straight & lanes,plain flow,quiet roads,climb,flat). Ferries are never used.Route explanation. Per route: km by road class, km on cycle infrastructure, main-road km, stop events by cause, turns, detected climbs (length, gain, grade), ascent and descent from DEM-sampled elevations.
GPX export with elevation, ready for Garmin Connect (Training & Planning > Courses > Import).
Web UI (Leaflet, single file) with click-to-pick start and end, place search, sliders for every setting, route cards and a cycle-infrastructure overlay.
MCP server exposing
plan_route,route_details,export_gpx,geocode,list_presets,pick_points,statusandstart_brouter.
Related MCP server: livedot MCP
Quick start
Prerequisites: uv (brew install uv), Java 17+
(for BRouter), curl, and Node (only for the UI syntax check).
make setup # uv sync
make planner-setup # once: downloads BRouter 1.7.10 + Ireland tiles into data/brouter/, builds the flow index
make brouter # terminal 1: BRouter on http://localhost:17777
make planner # terminal 2: planner on http://localhost:8081Open http://localhost:8081, click a start and an end (or search by name) and
pick a mode. make planner-check runs pytest, ruff and the UI syntax check.
Data you need to provide
The data/ directory is gitignored apart from small samples and the stop
model. Before make planner-setup you need:
path | what | where from |
| OSM extract | |
| stop-cause events |
|
| Copernicus GLO-30 tiles (optional, needed for | AWS Open Data, see |
BRouter's routing tiles are downloaded by the setup script. The committed stop
model (data/model/stop_model.json) defaults to a literature-based prior; the
empirical weight sets were derived offline from one rider's history, which is
not in the repo.
Use it from Claude Code
The repo ships a project-scoped .mcp.json that registers the planner as the
flow-planner MCP server (uv run scripts/flow_mcp.py). Start Claude Code in
the repo, approve the server, make sure BRouter is running (or ask for
start_brouter), then:
Plan a 60 km climbing loop from Rathfarnham.
Out and back from Howth to Donabate, 50 to 60 km, keep me off the main roads.
Export the best one for my Garmin.
Details, the full tool table and the evaluation results are in docs/mcp.md.
How it works
The web page or MCP tool calls
PlannerServiceinscripts/flowplan/.BRouter is asked for candidates with the custom
profiles/flow.brfprofile: four cost variants times four alternatives per leg, plus via-point sets for loops and out-and-backs, under a call budget.Near-duplicate candidates are dropped, the rest are matched to the flow index (
data/flow/ireland.index.csv) and scored by the stop model.Routes are ranked by the objective, climbs are detected on a DEM-sampled profile, and the top
nare returned with explanations and GPX.
docs/planner.md covers the architecture, the stop model, the BRouter profile, loop geometry, elevation sources and known limits.
Repository layout
path | contents |
| planner library: BRouter client, candidates, scoring, ranking, climbs, terrain (DEM), turns, GPX, service |
| FastAPI web server and |
| MCP server (FastMCP, stdio) |
| data pipeline and research scripts (OSM features, flow index, stop-model validation, evals) |
| the BRouter profile with node costs per stop cause, lane and main-road factors |
| the planner page |
| pytest suite (BRouter is mocked; no network needed) |
| planner and MCP documentation, evaluation tables |
| the feasibility study, one note per question |
| Leaflet viewer over the study's sample outputs |
| small committed data: eval CSVs, sample GPX, the stop model |
| issue tracker export (see below) |
Research
The planner rests on a set of research notes in docs/research/, each following one template, starting from the feasibility summary: OSM tag coverage in Ireland, OSM stop-cause features, empirical stop detection from ride GPS, validation of the stop model against observed stops, open elevation models checked on the Wicklow Gap, open climb datasets, motor-traffic counts, routing engines compared on node-level costs, and open sources for stop priors.
Development
make planner-checkis the gate: pytest,ruff check, and a syntax check of the inline UI script.Evaluations:
uv run scripts/plan_eval.py(loop, out-and-back and one-way scenarios against a live BRouter) anduv run scripts/planner_eval.py(one-way pairs). Results are committed underdata/samples/and discussed in the docs.Issues are tracked with beads (
bd). The versioned export is.beads/issues.jsonl; runbd primefor the workflow. The commit history is one commit per bead, sogit logreads as the project's change log.The code was written with Claude Code acting as implementer and reviewer under a human orchestrator;
CLAUDE.mdandAGENTS.mdhold the agent instructions.
Data licences
Map data (c) OpenStreetMap contributors, ODbL. Derived tables (the flow index, the stop-cause events, the committed samples) are derived databases under the ODbL.
Elevation: Copernicus DEM GLO-30, (c) European Union, Copernicus free licence.
Routing: BRouter (MIT), downloaded at setup, not vendored.
Licence
MIT, see LICENSE.
Available Tools
8 toolsexport_gpxB
Write a planned route as GPX 1.1 (with elevation) into out_dir (must exist; absolute or ~).
Inputs: route_id (required), name, out_dir. Returns: result
geocodeB
Look up an Irish place name (Nominatim). Returns candidates with name and lat,lon.
Inputs: query (required), limit. Returns: result
list_presetsA
Settings presets (straight & lanes, plain flow, climb, flat) as dicts: pass settings to plan_route
and objective as plan_route's objective argument.
Inputs: no named parameters. Returns: result
pick_pointsA
Ask the user to click 1 or 2 points on the planner map (opens the browser at the planner web page, which
needs make planner running) and wait for them. Returns 'lat,lon' strings to use as start / end in plan_route.
Inputs: n, timeout_s. Returns: result
plan_routeA
Plan routes. mode: loop | out_and_back | one_way. start/end: 'lat,lon' or a place name (geocoded; the resolved place is echoed). Loops and out-and-backs need length_km (+-10%) or min_km and max_km; one_way needs end and ignores length. objective: flow (fewest stops/turns) | climb | flat. return_mode: same | free. settings: optional dict from list_presets (e.g. turn_cost, lane_bonus, weights; main_road_penalty 1..5 multiplies the cost of primary, secondary and trunk roads, 2.5 = 'quiet roads' preset). Loops take 30-60 s. Returns a markdown table of ranked routes (use the ids with route_details / export_gpx) plus plan notes.
Inputs: mode (required), start (required), n, end, +7 more. Returns: result
route_detailsB
Explain a planned route: km by road class, cycle-infrastructure km, stop events, climbs, turns.
Inputs: route_id (required). Returns: result
start_brouterA
Start the local BRouter server (scripts/run_brouter.sh serve) if it is not reachable; waits up to 60 s.
Inputs: no named parameters. Returns: result
statusC
BRouter reachability, region, stop-model weight set, flow index size and DEM coverage.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 8 tools
Each tool has a clearly distinct role in the route-planning workflow: planning, inspecting, exporting, presets, point picking, geocoding, status, and starting BRouter. There is no meaningful overlap; plan_route returns route IDs while route_details and export_gpx consume them.
Most names follow a predictable snake_case verb_noun or noun pattern (route_details, export_gpx, list_presets, pick_points, start_brouter, plan_route). A few deviations like status and geocode are single-word but still clear and readable.
Eight tools is well-scoped for a route-planning server, with each tool covering a necessary step from setup to output. No tool feels redundant or missing from the count.
The surface covers the core lifecycle: discover places, configure settings, plan routes, inspect details, and export GPX. Minor gaps exist around managing multiple saved routes or re-inspecting previously planned routes beyond the immediate result set.
Maintenance
Related MCP Connectors
Turn Claude or ChatGPT into a cycling coach that plans your week, grades it, and adapts. Free beta.
Location tools for Claude and other MCP clients, strongest in the US and Great Britain. Geocode whole lists with a confidence score per row, filter by distance, get road distances and drive-time areas, and plan multi-driver routes with Google Maps links. Check flood zones, crime and live warnings, find nearby places and UK registers (NHS, CQC, food hygiene), and keep shareable maps. Reads and writes Google Sheets. Free: sign in with Google.
Connect Intervals.icu to Claude and ChatGPT: read training, plan workouts. Training never stored.
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Related MCP Servers
- AlicenseAqualityBmaintenanceProvides Claude Code and Claude Desktop with safe, read-only access to your local Garmin training data, readiness decisions, run details, and trends so you can get coaching advice in natural language.15164 PyPI9MIT
- AlicenseNot gradedqualityCmaintenanceEnables users to ask ChatGPT or Claude where a runner or cyclist is in a live race, how the race is going, and what the weather along the course will be, returning live maps and 3D route flyovers inline in the chat. Also surfaces cycling tour day-by-day routes, GPX links and organiser notes, all read-only and free.MIT
- AlicenseAqualityBmaintenanceEnables Claude to generate mountain bike loops or point-to-point routes from a place name or coordinates, computed on real OpenStreetMap trails by a routing engine and saved as GPX files with elevation, along with a summary and warnings about traffic, steep grades, protected areas and forbidden access. It also lists previously saved routes.2MIT
- AlicenseNot gradedqualityNot gradedmaintenanceConnects Garmin training data to Claude so it can read recent activities, wellness and recovery signals, and upcoming calendar events. It also lets Claude create, update, and delete structured workouts that sync through intervals.icu to Garmin Connect and onto the user's watch.MIT