hike-finder

hike-finder

Finds marked hiking routes from OpenStreetMap filtered by locally-computed elevation gain, distance, loop shape, and car/chairlift access, providing consistent and tunable metrics instead of third-party scraped data.

Category
访问服务器

README

hike-finder-mcp

Find marked hiking routes from OpenStreetMap and filter them by real, locally-computed elevation gain and distance — not numbers scraped from trail-description websites — plus shape and access: whether a route is a loop, and whether you can reach it by car or chairlift.

It runs three ways on one engine: a command-line tool, a local web UI (a map you pan to your area), or an MCP server for LLM clients. The CLI and web UI need no LLM and no MCP client — they're plain standalone programs.

It targets OSM route relations (route=hiking/foot), the same signed, maintained trail data — including the Czech KČT network — that mapy.cz renders. Distance and elevation gain are computed in this codebase, so the numbers are consistent and tunable instead of inherited from a third party.

Why this exists

Trail sites (AllTrails, Komoot, mapy.cz) all report different gain for the same trail because elevation gain depends entirely on how you sample and de-noise the terrain. This tool makes that step explicit and consistent: it resamples each track to even spacing, smooths the elevation series, and counts climbs with a hysteresis threshold so DEM noise isn't mistaken for ascent.

Filters

find_hikes(south, west, north, east, …) takes these optional filters:

Filter Meaning Confidence
min_gain_m / max_gain_m elevation gain bounds (m), computed locally high
min_distance_km / max_distance_km route length bounds high
circular true = loops only, false = point-to-point only high
car_access true/false: is amenity=parking mapped near a trail end? best-effort
chairlift_access true/false: is a ride-up aerialway (chairlift/gondola/cable car) mapped near a trail end? best-effort

The three boolean filters are tri-state: omit = don't care, true = require, false = exclude. Honesty note: car_access/chairlift_access reflect OSM mapping, not the world — a false means nothing of that kind is mapped near the route's ends, not that it's impossible to get there. Loop detection is reliable.

Internally the search is two-pass: cheap geometry/shape/access filters run first and a long through-route that merely crosses the area is dropped, so the elevation backend is only queried for routes that already match.

Two elevation backends (both supported)

Mode Source Setup Accuracy Limits
api Open-Elevation / OpenTopoData none coarser rate-limited (per-sec throttle + daily counter, both managed)
local SRTM/ASTER GeoTIFF tiles download tiles once high none
auto local if available, else api optional tiles best available graceful fallback

Set via HIKE_ELEVATION_MODE. See src/hike_finder/config.py.

Quickstart

pip install -e .                   # CLI + web UI; no LLM / MCP stack required

# browser: pan a map to your area, set filters, search
hike-finder-web                    # then open http://127.0.0.1:8765

# terminal: one command, prints results
hike-finder --bbox 50.72 15.58 50.74 15.62 --circular --user-agent you@example.com

Using it

Three frontends, one engine. The CLI and web UI need no LLM and no MCP client.

Install

pip install -e .                  # base: the `hike-finder` CLI and `hike-finder-web` UI
pip install -e ".[mcp]"           # + the MCP server (`hike-finder-mcp`)
pip install -e ".[local-dem]"     # + the local GeoTIFF DEM elevation backend (needs rasterio)
pip install -e ".[dev]"           # + pytest

Extras combine: pip install -e ".[mcp,local-dem]".

Set a contact for Overpass. OSM's public server rejects the default User-Agent with 406. Provide a real email/URL via --user-agent (CLI), the Contact field (web UI), or HIKE_OVERPASS_UA=you@example.com in the environment — per OSM etiquette.

Option A — Web UI (easiest; no coordinates to type)

hike-finder-web                   # serves http://127.0.0.1:8765 (--host/--port to change)

Open it, pan/zoom the map to your area, fill in the contact field, choose filters (shape, car/chairlift access, gain and distance ranges), then click "Search this map area". Matches are listed and pinned at their start point — click one to jump to it. This is the answer to "how do I get a bounding box": you draw it by moving the map. Pure standard library, no web-framework dependency.

Option B — Command line

hike-finder --bbox 50.72 15.58 50.74 15.62 \
            --circular --chairlift-access \
            --user-agent you@example.com

--bbox is south west north east (min-lat min-lon max-lat max-lon). The three boolean filters are tri-state: omit = don't care, --circular = require, --no-circular = exclude (same for --car-access and --chairlift-access). Numeric filters: --min-gain/--max-gain (m), --min-distance/--max-distance (km). Add --json for machine-readable output. hike-finder --help lists all.

Each match prints as one line:

<name> — <km> km, +<gain> m / -<loss> m [loop, car, lift:chair_lift] (start <lat>,<lon>, OSM relation <id>)

The [...] flags: loop/one-way, then car and/or lift:<type> when access is mapped near an endpoint.

Option C — MCP server (drive it from an LLM client)

Needs the mcp extra. Register the hike-finder-mcp command:

claude mcp add hike-finder --env HIKE_OVERPASS_UA=you@example.com -- hike-finder-mcp

.mcp.json / Claude Desktop config (equivalent):

{
  "mcpServers": {
    "hike-finder": {
      "command": "hike-finder-mcp",
      "env": { "HIKE_OVERPASS_UA": "you@example.com" }
    }
  }
}

Then ask in plain language ("find loop hikes near Špindlerův Mlýn reachable by chairlift") and the client calls find_hikes(south, west, north, east, …) with the same filters as the CLI.

The MCP registration form isn't live-verified in this repo (the build env has no mcp SDK). The SDK's decorator API has shifted across versions — if the server won't start, check the imports in src/hike_finder/server.py against your installed mcp version (see HANDOFF.md).

Getting a bounding box (CLI / MCP)

The web UI gives you the box for free. For the CLI or MCP you supply four corners in the order south, west, north, east (min latitude, min longitude, max latitude, max longitude):

  • openstreetmap.org → "Export" tab draws a draggable box and shows its four edges — copy them straight in.
  • Or read the corners off mapy.cz for the area you're planning.

Validated live (2026-06-23): the bbox 50.72,15.58,50.74,15.62 (Špindlerův Mlýn) returned 12 routes (each flagged for car/lift/shape), with a computed gain/loss for every one — e.g. [Z] Richtrovy Boudy → Špindlerův mlýn at +678 m / −251 m. The detected loop Špindlerův mlýn – okruh came back +34 m / −34 m — gain ≈ loss, exactly as a closed loop must, which cross-checks the whole sampling/gain pipeline. Loop detection was also validated live (2026-06-23) against the real "Medvěd*" relations — which caught and corrected an over-reporting bug; closure now reads the member ways as a vertex graph (circuit rank), independent of way-stitching. Distance was also hardened here (2026-06-23): it now sums every member way's length rather than the greedily-stitched line, so branched relations that the stitch couldn't chain no longer under-count (validated live by a per-route stitched-vs-summed diff). Remaining caveat: the local DEM backend (mode=local) is still untested, and the trail's start/endpoints (used for car/lift access) still come from the greedy stitch on branched relations — both tracked in HANDOFF.md.

Configuration (environment variables)

All optional except where noted; defaults come from src/hike_finder/config.py.

Variable Meaning Default
HIKE_OVERPASS_UA User-Agent for Overpass — required by the public server; use a real contact generic UA naming no contact
HIKE_OVERPASS_URL Override the Overpass endpoint (use a regional/self-hosted instance for heavy use) overpass-api.de
HIKE_ELEVATION_MODE api | local | auto auto
HIKE_DEM_DIR GeoTIFF DEM tile directory (for local/auto)
HIKE_API_ENDPOINT Override the elevation API endpoint provider default
HIKE_API_MIN_INTERVAL Min seconds between elevation-API requests (keeps you under the public ~1 req/sec limit) 1.1
HIKE_API_MAX_RETRIES Retries on transient API errors (429 / 5xx / network), with exponential backoff honouring Retry-After 3
HIKE_API_BACKOFF Backoff base seconds, doubled each retry 2.0
HIKE_API_MAX_BACKOFF Cap on any single wait, seconds; a Retry-After above this (e.g. a daily-quota 429) makes the route degrade to n/a instead of stalling 30
HIKE_API_DAILY_LIMIT Max elevation-API requests per UTC day, counted in a persistent file across runs; at the cap, routes degrade to n/a instead of getting the IP banned. 0 disables tracking 1000
HIKE_API_STATE_DIR Directory holding the daily-counter file per-user cache (%LOCALAPPDATA%/hike-finder or ~/.cache/hike-finder)
HIKE_GAIN_THRESHOLD Hysteresis climb threshold, metres (must exceed peak-to-peak DEM noise) 10
HIKE_SAMPLE_INTERVAL Resample spacing along the track, metres 25
HIKE_SMOOTH_WINDOW Elevation smoothing window, samples 3
HIKE_LOOP_TOLERANCE start≈end distance that closes a loop, metres 150
HIKE_CAR_RADIUS Parking-near-endpoint radius, metres 300
HIKE_LIFT_RADIUS Lift-station-near-endpoint radius, metres 400
HIKE_MAX_ROUTE_FACTOR Drop routes longer than this × the bbox diagonal (kills through-routes) 4.0

Troubleshooting

  • 406 Not Acceptable / every Overpass request fails → set HIKE_OVERPASS_UA to a real contact. The public server rejects the default Python User-Agent.
  • No hikes returned → widen the bbox or loosen the filters. Note that loops are genuinely sparse in KČT data (most relations are linear marked segments), so circular=true legitimately returns few results.
  • Slow / occasional 504 → public Overpass overload; the client retries with backoff. Point HIKE_OVERPASS_URL at a regional instance for heavy use.

Status

Core geometry, gain, access/shape math, the Overpass response parser, the elevation-API client (including its rate-limit throttle, transient-error retry/backoff, and a persistent daily-request counter that degrades to n/a before blowing the API's daily cap), and the CLI argument/formatter layer: implemented and unit-tested (72 tests, all offline). The Overpass HTTP call and the API elevation backend are validated live (CLI + web), with computed gain cross-checked against the loop invariant (gain ≈ loss). The local-DEM backend and the MCP entry point are implemented; validate on a networked machine. See HANDOFF.md for exactly what's done and what's next.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选