Bike Router

io.github.JonasHeinickeBio由 GitHub 帳號 JonasHeinickeBio 發布v0.3.0更新於 Oct 29, 2026

Plan bike routes with a self-hosted OSM service: facts only, with weather and sights.

發布方自己的服務:370.ai — AI Gateway: 100+ Chat Models, Image & Speech Generation

已驗證STDIO僅桌面位置與生活開發者工具

概覽

AI 產生的概覽

連接自架 pyBikeRouter API 的 MCP 伺服器,可規劃以 OSM 為基礎的單車路線,並附上天氣、景點與 GeoJSON/GPX 匯出。

可以做什麼
  • 依地名或座標規劃單車路線,可指定車種與限制條件
  • 取得含評分、距離、爬升與警示的多條候選路線,以及只陳述事實的說明
  • 將路線匯出為 GeoJSON 或 GPX,並查找路線附近的景點
  • 依出發時間提供沿途天氣預報
  • 地名有歧義時要求澄清,而不是猜測位置
適用情境
當你已自行執行 pyBikeRouter 服務,並希望助理在對話或代理流程中規劃、比較與說明單車路線(含天氣與景點)時使用。
執行需求
透過 uvx 從 bike-router PyPI 套件啟動的本機程序,並需要一個執行中的 pyBikeRouter API,其位址由 BIKE_ROUTER_API_URL 指定。該 API 通常還需要 openrouteservice API 金鑰(ORS_API_KEY)以及用於地理編碼的網路存取。
安裝前請注意
此伺服器只會存取 BIKE_ROUTER_API_URL 指向的 API,請確認指向可信任的執行個體。若 API 設定了資料庫,路線規劃可能被寫入歷史紀錄。路線不構成安全保證,地圖資料也可能不完整。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Bike Router,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

bike-routing-agent

[CI]

An OSM-based bike-routing service: a typed, provider-neutral domain model, a full openrouteservice API client plus routing adapter, and a LangGraph workflow that turns a validated route request into an explainable, exportable cycling route.

The LLM (where used) may parse free text, ask clarification questions, and explain a chosen route. It never invents coordinates, geometry, elevation, or route suitability -- all of that comes from OSM-derived routing engines.

Easy install (no programming needed)

Download pybikerouter-easy-<version>.zip from the Releases page, unzip it, install Docker Desktop, and double-click the Start file for your computer. The first start asks one question -- where you ride -- downloads that area's map data, and opens the planner in your browser. Step by step, in plain words: docs/easy-install.md (and START-HERE.txt in the download).

Documentation

The full documentation suite lives in docs/:

DocumentContents
ArchitectureGraph nodes, state, branching, terminal statuses, error model
APIEndpoint contracts, response statuses, artifact serving
ConfigurationEvery environment variable, validation rules, deployment notes
ProvidersProtocols, ORS client/adapter behaviour, geocoders, BRouter/Valhalla adapters, adding a backend
Backend comparisonMeasured ORS vs BRouter behaviour per bike type, combining both engines
GeocodingNominatim vs Pelias, confidence/ambiguity semantics, tuning
Scoring & exportsScore math, uncertainty policy, explanation rules, GeoJSON/GPX
Plan from wordsDescribe a ride in a sentence; an optional LLM turns it into the structured request (never coordinates)
WeatherForecast along the route at your departure time: temperature, rain, wind vs. riding direction (free, keyless providers)
Self-hosted stackRun routing and/or geocoding locally from one OSM extract; hardware requirements and small-PC options
TestingTest layout, mocking conventions, live tests, CI
Web plannerPutting places into the trip; click a point on the map and choose where in the route it goes
iPhone / TailscaleUse the planner from an iPhone as a home-screen app over your tailnet
RoadmapPlanned work and explicit non-goals

Architecture

FastAPI  |  vLangGraph RouteAgentState  |  +--> parse_request        (structured input first; LLM extraction is an injectable dependency)  +--> validate_request      (Pydantic)  +--> geocode_locations     (Nominatim by default, public or self-hosted; ambiguity -> clarification, never a guess)  +--> route_with_provider   (openrouteservice; engine-neutral RoutingRequest in, RouteCandidate out)  +--> score_candidates      (deterministic distance/elevation/warning scoring)  +--> explain_and_export    (facts-only explanation + GeoJSON/GPX export)  |  vJSON response + GeoJSON/GPX artifacts

Graph branches:

START -> parse_request      -> validate_request -> (invalid | awaiting_clarification) -> END      -> geocode_locations -> (awaiting_clarification | provider_failure) -> END      -> route_with_provider -> (no_route | provider_failure) -> END      -> score_candidates -> (no_route) -> END      -> explain_and_export -> END

Every path ends with an explicit status; the graph never calls a routing provider unless validation and geocoding both succeeded, and it never returns without a terminal status.

Setup

Requires Python 3.11+ and Poetry.

bash
poetry installcp .env.example .env

poetry install creates an in-project virtualenv (.venv/, see poetry.toml) with both runtime and dev dependencies. Run any command inside it with poetry run <command>, or poetry shell to activate it directly.

Edit .env and set ORS_API_KEY to a valid openrouteservice API key.

Environment variables

VariablePurposeDefault
ORS_API_KEYopenrouteservice API key(required for live routing)
ORS_BASE_URLopenrouteservice base URLhttps://api.openrouteservice.org
ORS_TIMEOUT_SORS request timeout (seconds)10.0
ORS_MAX_RETRIESRetries for timeouts/5xx2
GEOCODER_PROVIDERGeocoder backend: nominatim (public or self-hosted) or pelias (needs a Pelias API behind ORS_BASE_URL, see docs/geocoding.md; refuses the public ORS URL at startup)nominatim
GEOCODER_BASE_URLNominatim base URL (ignored when GEOCODER_PROVIDER=pelias)https://nominatim.openstreetmap.org
GEOCODER_TIMEOUT_SGeocoder request timeout5.0
GEOCODER_USER_AGENTRequired by Nominatim's usage policybike-routing-agent/0.1
GEOCODER_CACHE_TTL_SIn-memory geocode cache TTL3600
GEOCODER_AMBIGUITY_MARGINConfidence gap below which top-2 results are "ambiguous"0.05
GEOCODER_MIN_CONFIDENCEMinimum confidence to auto-accept a top result0.3
VALHALLA_BASE_URLBase URL of a self-hosted Valhalla (meili) serverhttp://localhost:8002
VALHALLA_TIMEOUT_SPer-request Valhalla timeout (seconds)30.0
VALHALLA_MAX_RETRIESRetries for Valhalla timeouts/5xx1
EXPORT_DIRLocal directory for GeoJSON/GPX artifactsexports
DATABASE_URLPostgreSQL/PostGIS URL: records route history, enables /v1/history/* (docs/persistence.md)unset
ARTIFACT_BACKENDlocal or database (artifacts stored in PostgreSQL)local
LOG_LEVELLog levelINFO

Running the API

bash
poetry run uvicorn bike_routing_agent.api:app --reload

The app also serves a built-in web UI (map-based route planner) at http://localhost:8000/, with the interactive API docs at /docs.

Command-line interface

Installing the package exposes a bike-router command (also runnable as python -m bike_routing_agent.cli) organised into subcommand groups:

bash
bike-router route plan --origin "Berlin Hbf" --destination "Potsdam" \    --bike-type gravel --target-distance-km 30 --output plan.jsonbike-router serve start --port 8000bike-router docker up            # docker compose -f docker/compose.yaml up -d --buildbike-router docker logs -fbike-router config show          # effective settings, secrets redactedbike-router config check         # validate settings against the environmentbike-router providers list       # provider names and bike-type -> ORS profile mapbike-router profile settings --bike-type touring   # what a request may tune (route plan --profile-param), from the LinkML schemabike-router route plan ... --format text --gpx best.gpx   # alternatives, sight stops, exportsbike-router route show plan.json # a saved plan again; `route export` writes any alternativebike-router poi along --route plan.json   # sights near a route, ranked by famebike-router brouter needed|info|download  # BRouter map tiles (asks before downloading)bike-router history list|show|stats       # past plans (needs DATABASE_URL)bike-router status show          # readiness of every component and the active featuresbike-router chat start           # plan routes by chatting (docs/chat.md)

Everything the API and the web form do is available from the CLI -- see docs/cli.md.

route plan --text "50 km gravel loop from Braunschweig" uses the optional LLM parser (docs/llm-parser.md).

route plan accepts lat,lon pairs or place text for --origin, --destination and repeated --via waypoints, prints the JSON result and exits 0 on ready, 1 on clarification/provider failure, 2 on usage errors. With DATABASE_URL set it also records the plan in the route history (best effort; plan_id in the output, --no-record to skip), a forecast along the route at --departure-time (docs/weather.md), and bike-router db migrate / db status manage the schema (docs/persistence.md).

Running with Docker

All container assets live in docker/:

bash
cp .env.example .env        # set ORS_API_KEYdocker compose -f docker/compose.yaml up --build

Open http://localhost:8000/ for the web UI. Route artifacts are stored in the named pybikerouter-exports volume. See docs/self-hosted.md for the optional local routing / geocoding stack -- including what it needs and how to run just one half on a small machine.

Example request

bash
curl -X POST http://localhost:8000/v1/route/plan \  -H 'Content-Type: application/json' \  -d '{    "origin": "Braunschweig Hauptbahnhof",    "destination": "Wolfenbüttel",    "constraints": {      "bike_type": "gravel",      "avoid_high_traffic_roads": true,      "max_ascent_m": 500    }  }'

Example response

json
{  "status": "ready",  "route": {    "provider": "ors",    "provider_profile": "cycling-regular",    "geometry_geojson": {"type": "LineString", "coordinates": []},    "metrics": {      "distance_m": 12500,      "duration_s": 2700,      "ascent_m": 85,      "descent_m": 90,      "surface_coverage": {},      "unknown_surface_fraction": null    },    "score": 0.91,    "score_breakdown": {"distance_fit": 1.0, "elevation_fit": 1.0, "warning_penalty": 0.0},    "warnings": [],    "provenance": {"provider": "ors", "profile": "cycling-regular"}  },  "candidates": [    {"provider": "ors", "provider_profile": "cycling-regular", "score": 0.91},    {"provider": "brouter", "provider_profile": "trekking", "score": 0.84}  ],  "explanation": "...",  "artifacts": {    "geojson_url": "/v1/routes/<id>.geojson",    "gpx_url": "/v1/routes/<id>.gpx"  },  "clarification": [],  "errors": []}

If origin/destination are ambiguous or unresolved, status is awaiting_clarification and clarification lists the candidate places to choose from -- no route is generated from a guess.

Bike types

constraints.bike_type selects the routing profile per engine and defaults to gravel. Supported values: road, gravel, touring, mountain, city, ebike, commuter (fast, low-traffic), recumbent. ORS ships four cycling profiles, so e.g. ebike uses cycling-electric while commuter rides on cycling-regular; the self-hosted BRouter provider differentiates further -- gravel, touring, mountain, city, commuter and recumbent each get their own profile, while road and ebike share fastbike (BRouter has no e-assist cost model) (see docs/configuration.md).

Make targets

make lists the everyday commands; they use the project's .venv (or the active environment):

bash
make install       # poetry installmake hooks         # the git hooks (commit: lint + types; push: the whole suite)make run           # the API with auto-reload (HOST=127.0.0.1 PORT=8000)make check         # lint + types + tests without coverage, stops at the first failuremake ci            # what CI runs: lint, types, tests with the 80 % coverage floormake test-fast ARGS="tests/nodes -k geocode"     # a part of the suite (no coverage floor)make deploy        # build and restart the local container (bike-router deploy up)

Linting and type checking

bash
poetry run ruff check .poetry run mypy src

Both run in CI on every push and pull request (see .github/workflows/ci.yml).

Running tests

bash
poetry run pytest

Coverage is collected on every run and the suite fails below 80% (--cov-fail-under=80 in tool.pytest.ini_options.addopts; currently 97% total, every module ≥84%).

Live tests that hit real external services are marked @pytest.mark.live and excluded by default (see tool.pytest.ini_options.addopts in pyproject.toml). Run them explicitly with:

bash
poetry run pytest -m live

Pre-commit hooks

Quality gates run automatically before each commit/push via pre-commit. Install both git hook stages once after poetry install:

bash
poetry run pre-commit install --hook-type pre-commit --hook-type pre-push

On commit it runs whitespace/EOF/YAML/TOML/merge-conflict/large-file checks, ruff check --fix and mypy src; the full pytest suite runs only in the pre-push stage on git push (mirroring CI). Run the commit stage manually with poetry run pre-commit run --all-files and the pre-push stage with poetry run pre-commit run --hook-stage pre-push --all-files.

Known limitations

  • OSM tag completeness varies by region; surface/access metadata is frequently missing and is represented as uncertainty, not treated as favorable.
  • Routing engines (ORS, Valhalla, BRouter) map bike categories to their own profiles differently; the mapping in config.py is an approximation, especially for gravel riding.
  • Elevation data (ascent/descent) varies in accuracy between providers and is not always available.
  • No route produced by this service is a safety guarantee. Explanations use hedged language ("better aligned with available map metadata") rather than claims like "safe route".
  • BRouter and Valhalla are wired up end to end but only against self-hosted deployments (ROUTING_PROVIDER=brouter / valhalla / all, BRouter via the compose profile in docker/brouter/README.md), and openrouteservice remains the default engine.
  • The Pelias geocoder option needs a Pelias API served at <ORS_BASE_URL>/pelias/v1: neither the public api.openrouteservice.org nor a stock self-hosted ORS provides one, and the adapter has only been tested against mocks (see docs/geocoding.md). For a local geocoder use the self-hosted Nominatim.

Repository layout

src/bike_routing_agent/├── api.py            FastAPI app (POST /v1/route/plan)├── config.py          Settings + provider profile mapping├── models.py          Pydantic v2 domain models├── state.py            LangGraph RouteAgentState├── graph.py            LangGraph wiring├── errors.py           Structured provider/geocoding errors├── providers/         GeocodeProvider / RoutingProvider adapters│                      (ors_client.py: full ORS client -- directions, export,│                       isochrones, matrix, snap, POIs, Vroom, elevation,│                       Pelias geocoding, health; ors.py: the RoutingProvider;│                       geocoder.py: Nominatim; pelias.py: Pelias on│                       self-hosted ORS)├── nodes/              One module per graph node├── scoring/            Deterministic route scoring├── exporters/          GeoJSON / GPX export├── frontend/           Static web UI served at /└── cli/                bike-router command line (route/serve/docker/config/providers)docker/                 Dockerfile + compose.yamltests/├── fixtures/           Sample provider responses├── nodes/               One test module per graph node├── providers/          Adapter unit tests (mocked HTTP)├── graph/              Graph branch tests├── exporters/          Export format tests└── live/                Tests marked @pytest.mark.livedocs/                   Documentation suite (see docs/README.md)

Licence

MIT, see LICENSE.

Third-party licences

BRouter (MIT) and the OpenStreetMap data (ODbL) this project builds on are credited, with the full BRouter licence text, in THIRD_PARTY_LICENSES.md.

來源:README.md,提交 bc2d1da

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v0.3.0最新Oct 29, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

其他 Router 整合