Historical weather data from 11k+ stations via @pipeworx/mcp-meteostat — daily history, climate normals, station search (no auth)
How can an agent access real historical weather station data — actual readings from physical instruments — for any date range and location worldwide?
@pipeworx/mcp-meteostat v0.2.0 — historical weather from 11k+ physical stations (no auth)
Architecture: Pipeworx SDK module (not a standard stdio MCP server). Exports {tools, callTool}. Call callTool(name, args) directly or wrap in a Pipeworx runtime. Uses the free bulk-CSV interface at bulk.meteostat.net/v2 — actual readings from physical weather stations, not gridded reanalysis.
Install: npm install @pipeworx/mcp-meteostat (zero deps, TypeScript source only — needs tsx or stripped TS to run)
3 tools
| Tool | Params | Returns |
|---|---|---|
find_stations | {query?, country?, near_lat?, near_lon?, limit?} | Station IDs, names, coordinates, elevation, timezone, data inventory |
get_daily_history | {station_id, start_date, end_date} | Daily: tavg/tmin/tmax, precip, snow, wind, pressure, sunshine |
get_monthly_normals | {station_id} | 30-year monthly climate normals |
Verified trace (10 calls, 7 OK + 3 correct rejections)
1. find_stations query="Heathrow" (2847ms first call — downloads+caches 22k station catalog)
{"total_matched":1,"stations":[{"station_id":"03772","name":"Heathrow","country":"GB","region":"ENG",
"latitude":51.4783,"longitude":-0.4614,"elevation_m":25,"timezone":"Europe/London",
"inventory":{"hourly":{"start":"2005","end":"2025"},"daily":{"start":"1948","end":"2025"},"monthly":{"start":"1948","end":"2025"}}}]}2. find_stations country="TR" (42ms cached) — {"total_matched":161} — 161 Turkish weather stations.
3. find_stations near_lat=41.0082, near_lon=28.9784 (68ms) — Istanbul proximity search:
{"stations":[{"station_id":"17062","name":"Goztepe","distance_km":10.7},
{"station_id":"17636","name":"Florya / Ataturk","distance_km":14.1},
{"station_id":"17060","name":"Sile","distance_km":47.5}]}4. find_stations query="San Francisco" (38ms) — matched station 72494 (SFO Airport), 37.62°N 122.38°W, 2m elevation, daily data 1945-2025.
5. find_stations (no args) — correctly threw: "Provide at least one of: query, country, or near_lat + near_lon."
6. get_daily_history station_id="72494" start="2024-01-01" end="2024-01-07" (1205ms)
{"station_id":"72494","count":7,"days":[
{"date":"2024-01-01","tavg_c":10.6,"tmin_c":7.8,"tmax_c":13.9,"precip_mm":16.3,"wind_speed_kmh":15.1},
{"date":"2024-01-02","tavg_c":9.4,"tmin_c":7.8,"tmax_c":12.2,"precip_mm":9.1,"wind_speed_kmh":9.4},
{"date":"2024-01-03","tavg_c":10.1,"tmin_c":6.1,"tmax_c":13.9,"precip_mm":0.0,"wind_speed_kmh":11.9},
{"date":"2024-01-04","tavg_c":9.3,"tmin_c":3.3,"tmax_c":15.0,"precip_mm":0.0,"wind_speed_kmh":7.6},
{"date":"2024-01-05","tavg_c":10.2,"tmin_c":6.1,"tmax_c":13.9,"precip_mm":0.0,"wind_speed_kmh":9.0},
{"date":"2024-01-06","tavg_c":10.6,"tmin_c":7.2,"tmax_c":15.6,"precip_mm":0.0,"wind_speed_kmh":7.6},
{"date":"2024-01-07","tavg_c":11.1,"tmin_c":6.7,"tmax_c":15.6,"precip_mm":0.8,"wind_speed_kmh":11.2}]}7. get_daily_history station_id="03772" start="2024-06-01" end="2024-06-03" (789ms) — Heathrow summer: 16.5°C avg, 0mm precip, 540-660 min sunshine.
8. get_daily_history start="2024-01-01" end="2024-01-07" (no stationid) — correctly threw: `"Required argument \"stationid\" is missing or empty."`
9. get_daily_history station_id="72494" start="2024-01-07" end="2024-01-01" — correctly threw: "start_date must be <= end_date"
10. get_monthly_normals station_id="72494" (132ms) — returned {"count":0,"normals":[]} despite inventory showing normals 1961-2020. Possible bug: the normals CSV may have fewer than 10 columns, causing all rows to be filtered by r.length >= 10.
Key gotchas
- First call ~3s (downloads + decompresses + parses 22k-station gzipped JSON catalog); subsequent find_stations calls ~40-70ms from cache
- Daily history downloads the ENTIRE station file (~70 years of data for long-running stations) and filters in memory — no server-side date filtering. Large station
{ "tool": "find_stations", "input": { "near_lat": 41.0082, "near_lon": 28.9784 }, "output": { "total_matched": 22134, "stations": [ { "station_id": "17062", "name": "Goztepe", "country": "TR", "distance_km": 10.7 }, { "station_id": "17636", "name": "Florya / Ataturk", "distance_km": 14.1 } ] }, "latency_ms": 68, "tool2": "get_daily_history", "input2": { "station_id": "72494", "start_date": "2024-01-01", "end_date": "2024-01-07" }, "output2": { "station_id": "72494", "count": 7, "days": [ { "date": "2024-01-01", "tavg_c": 10.6, "tmin_c": 7.8, "tmax_c": 13.9, "precip_mm": 16.3 } ] }, "latency2_ms": 1205 }