Wraps Open-Meteo's free weather APIs with eight MCP tools covering geocoding, 16-day forecasts, ERA5 historical climate back to 1940, marine conditions, CAMS air quality, and Copernicus terrain elevation. You geocode a place name to coordinates, then pull hourly or daily variables like temperature, precipitation, wind, wave height, or PM2.5. Historical queries over large date ranges spill to DataCanvas with SQL query tools for analysis. Supports both stdio and streamable HTTP transports, with a public hosted instance at open-meteo.caseyjhand.com. Useful when you need global weather context without API keys, or want to compare forecast models against reanalysis data in a single schema.
claude mcp add --transport http open-meteo https://open-meteo.caseyjhand.com/mcpRun in your terminal. Add --scope user to make it available in every project.
Review the command, arguments, and environment values before installing — MCP servers run with your local permissions.
Verified live against the running server on Jun 10, 2026.
openmeteo_geocodeResolve a place name to ranked coordinate matches with country, region, elevation, timezone, and population. Required prerequisite for name-based queries — all weather tools take latitude/longitude, not place names. Returns up to 10 matches ranked by population/relevance; use...3 paramsResolve a place name to ranked coordinate matches with country, region, elevation, timezone, and population. Required prerequisite for name-based queries — all weather tools take latitude/longitude, not place names. Returns up to 10 matches ranked by population/relevance; use...
name*stringcountintegerlanguagestringopenmeteo_get_elevationTerrain elevation from the Copernicus Digital Elevation Model (~90m resolution) for one or more coordinate pairs. Accepts up to 100 pairs per call. Useful for geographic context, elevation-adjusted weather interpretation, or route planning.2 paramsTerrain elevation from the Copernicus Digital Elevation Model (~90m resolution) for one or more coordinate pairs. Accepts up to 100 pairs per call. Useful for geographic context, elevation-adjusted weather interpretation, or route planning.
latitudes*arraylongitudes*arrayopenmeteo_get_forecastWeather forecast for coordinates: hourly and/or daily variables for up to 16 days ahead, with optional past_days (up to 92) for recent history. Use past_days instead of openmeteo_get_historical for dates within the last 1–5 days, since ERA5 has a variable lag. Returns per-time...10 paramsWeather forecast for coordinates: hourly and/or daily variables for up to 16 days ahead, with optional past_days (up to 92) for recent history. Use past_days instead of openmeteo_get_historical for dates within the last 1–5 days, since ERA5 has a variable lag. Returns per-time...
latitude*numbertimezonestringlongitude*numberpast_daysintegerforecast_daysintegerdaily_variablesarraywind_speed_unitstringkmh · mph · ms · kndefault: kmhhourly_variablesarraytemperature_unitstringcelsius · fahrenheitdefault: celsiusprecipitation_unitstringmm · inchdefault: mmopenmeteo_get_historicalHistorical weather from the ERA5 reanalysis archive (1940–present). Requires start_date and end_date (ISO 8601 date, e.g., "2024-07-01"). ERA5 has a variable lag of up to ~5 days — for dates within the last week, use openmeteo_get_forecast with past_days instead. Uses the same...11 paramsHistorical weather from the ERA5 reanalysis archive (1940–present). Requires start_date and end_date (ISO 8601 date, e.g., "2024-07-01"). ERA5 has a variable lag of up to ~5 days — for dates within the last week, use openmeteo_get_forecast with past_days instead. Uses the same...
end_date*stringlatitude*numbertimezonestringcanvas_idstringlongitude*numberstart_date*stringdaily_variablesarraywind_speed_unitstringkmh · mph · ms · kndefault: kmhhourly_variablesarraytemperature_unitstringcelsius · fahrenheitdefault: celsiusprecipitation_unitstringmm · inchdefault: mmopenmeteo_get_marineMarine weather forecast for a coastal or ocean coordinate: wave height, wave period, wave direction, wind-wave height, swell height, sea-surface temperature. Forecast horizon up to 7 days. Returns per-timestamp records — each entry contains a "time" field plus one key per requ...6 paramsMarine weather forecast for a coastal or ocean coordinate: wave height, wave period, wave direction, wind-wave height, swell height, sea-surface temperature. Forecast horizon up to 7 days. Returns per-timestamp records — each entry contains a "time" field plus one key per requ...
latitude*numbertimezonestringlongitude*numberforecast_daysintegerdaily_variablesarrayhourly_variablesarrayopenmeteo_get_air_qualityModeled CAMS (Copernicus Atmosphere Monitoring Service) air quality forecast: PM2.5, PM10, nitrogen dioxide, sulphur dioxide, ozone, carbon monoxide, dust, pollen, and European/US AQI indices. This is modeled grid data, not measured station readings — for measured data, use op...5 paramsModeled CAMS (Copernicus Atmosphere Monitoring Service) air quality forecast: PM2.5, PM10, nitrogen dioxide, sulphur dioxide, ozone, carbon monoxide, dust, pollen, and European/US AQI indices. This is modeled grid data, not measured station readings — for measured data, use op...
latitude*numbertimezonestringlongitude*numberforecast_daysintegerhourly_variablesarrayopenmeteo_get_ensembleProbabilistic ensemble weather forecast — up to 51 ensemble members, up to 16 days ahead with optional past_days (0–92). Each member's values appear as separate columns named with a member suffix (e.g. temperature_2m_member01, temperature_2m_member02). Use the spread across me...12 paramsProbabilistic ensemble weather forecast — up to 51 ensemble members, up to 16 days ahead with optional past_days (0–92). Each member's values appear as separate columns named with a member suffix (e.g. temperature_2m_member01, temperature_2m_member02). Use the spread across me...
modelsstringlatitude*numbertimezonestringcanvas_idstringlongitude*numberpast_daysintegerforecast_daysintegerdaily_variablesarraywind_speed_unitstringkmh · mph · ms · kndefault: kmhhourly_variablesarraytemperature_unitstringcelsius · fahrenheitdefault: celsiusprecipitation_unitstringmm · inchdefault: mmopenmeteo_get_floodGloFAS (Global Flood Awareness System) river discharge forecast and historical reanalysis. Returns daily ensemble river discharge (m³/s) for the river nearest to the given coordinates — no river ID needed, the API snaps to the nearest stream. Forecast horizon up to 210 days ah...7 paramsGloFAS (Global Flood Awareness System) river discharge forecast and historical reanalysis. Returns daily ensemble river discharge (m³/s) for the river nearest to the given coordinates — no river ID needed, the API snaps to the nearest stream. Forecast horizon up to 210 days ah...
end_datestringlatitude*numbertimezonestringlongitude*numberstart_datestringforecast_daysintegerdaily_variables*arrayopenmeteo_dataframe_queryRun a read-only SQL SELECT against tables staged on a DataCanvas by openmeteo_get_historical. Pass the canvas_id returned when openmeteo_get_historical spills (truncated: true). Tables are named by the spillover helper (e.g. spilled_<id>); use openmeteo_dataframe_describe to l...2 paramsRun a read-only SQL SELECT against tables staged on a DataCanvas by openmeteo_get_historical. Pass the canvas_id returned when openmeteo_get_historical spills (truncated: true). Tables are named by the spillover helper (e.g. spilled_<id>); use openmeteo_dataframe_describe to l...
sql*stringcanvas_id*stringopenmeteo_dataframe_describeList the tables and their columns on a DataCanvas staged by openmeteo_get_historical. Call this first to discover table names before querying with openmeteo_dataframe_query.1 paramsList the tables and their columns on a DataCanvas staged by openmeteo_get_historical. Call this first to discover table names before querying with openmeteo_dataframe_query.
canvas_id*stringGeocode places, fetch global weather forecasts, ERA5 historical climate, marine conditions, air quality, and terrain elevation via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://open-meteo.caseyjhand.com/mcp
Ten tools covering geocoding, weather forecasts, historical climate, probabilistic ensemble forecasts, marine conditions, air quality, terrain elevation, river discharge, and SQL analytics over large datasets:
| Tool | Description |
|---|---|
openmeteo_geocode | Resolve a place name to ranked coordinate matches with country, region, elevation, timezone, and population |
openmeteo_get_forecast | Weather forecast for coordinates: hourly and/or daily variables for up to 16 days, with optional recent past data |
openmeteo_get_historical | Historical weather from the ERA5 reanalysis archive (1940–present); large ranges spill to DataCanvas |
openmeteo_get_marine | Marine forecast for coastal or ocean coordinates: wave height, period, direction, swell, and sea-surface temperature |
openmeteo_get_air_quality | Modeled CAMS air quality forecast: PM2.5, PM10, NO2, O3, CO, dust, pollen, and European/US AQI indices |
openmeteo_get_elevation | Terrain elevation from Copernicus DEM (~90m resolution) for up to 100 coordinate pairs per call |
openmeteo_get_ensemble | Probabilistic ensemble forecast: per-member hourly/daily time series (up to 51 members, 16 days) for exceedance and uncertainty analysis |
openmeteo_get_flood | GloFAS river discharge forecast (up to 210 days) and reanalysis (1984–present); coordinate-based, snaps to nearest river |
openmeteo_dataframe_describe | List tables and columns on a DataCanvas staged by openmeteo_get_historical or openmeteo_get_ensemble |
openmeteo_dataframe_query | Run a read-only SQL SELECT against tables staged on a DataCanvas |
openmeteo_geocodeResolve a free-text place name to ranked coordinate matches. Required first step for name-based queries — all weather tools accept latitude/longitude, not place names.
count for disambiguation when common names (e.g., "Springfield") may match multiple citiestimezone parameterresults array (not an error) when no places matchopenmeteo_get_forecastWeather forecast for a coordinate pair with hourly and/or daily variable selection.
forecast_days 1–16, default 7)past_days (0–92) covers recent history via the forecast model — use instead of openmeteo_get_historical for dates within the last ~5 days to avoid ERA5 lagtemperature_2m, precipitation, wind_speed_10m, relative_humidity_2m, cloud_cover, uv_index, apparent_temperature, precipitation_probability, weather_code, surface_pressure, visibility, wind_direction_10m, wind_gusts_10m, dew_point_2mtemperature_2m_max, temperature_2m_min, precipitation_sum, wind_speed_10m_max, sunrise, sunset, uv_index_max, precipitation_hours, weather_codehourly_variables or daily_variables is requiredhourly_units / daily_units mapopenmeteo_get_historicalHistorical weather from the ERA5 reanalysis archive, covering 1940 to approximately 5 days ago.
start_date and end_date (YYYY-MM-DD); ERA5 has a variable ~1–5 day lagopenmeteo_get_forecast — past and forecast data are directly comparable on one schemahourly_variables or daily_variables is requiredCANVAS_PROVIDER_TYPE=duckdb — output includes canvas_id and truncated: true when the inline record limit is exceededopenmeteo_dataframe_describe with the canvas_id to list tables, then openmeteo_dataframe_query to run SQL SELECT against the staged dataopenmeteo_get_marineMarine weather forecast for coastal and open-ocean coordinates.
forecast_days 1–7, default 7)wave_height, wave_direction, wave_period, wind_wave_height, wind_wave_direction, wind_wave_period, swell_wave_height, swell_wave_direction, swell_wave_periodwave_height_max, wave_direction_dominant, wave_period_maxhourly_variables or daily_variables is requiredocean_current_velocity is null for non-open-ocean coordinatesopenmeteo_get_air_qualityModeled CAMS air quality forecast. Forecast-only — there is no historical archive for CAMS data.
forecast_days 1–7, default 5)pm2_5, pm10, carbon_monoxide, nitrogen_dioxide, sulphur_dioxide, ozone, dust, european_aqi, us_aqi, alder_pollen, birch_pollen, grass_pollen, mugwort_pollen, olive_pollen, ragweed_pollenhourly_variables is requiredopenaq-mcp-serverdata_source: "CAMS" to distinguish modeled from measured dataopenmeteo_get_elevationTerrain elevation from the Copernicus Digital Elevation Model (~90m resolution).
latitudes[] and longitudes[] arrays; both must have equal length (up to 100 pairs){ latitude, longitude, elevation_m }openmeteo_get_ensembleProbabilistic ensemble weather forecast exposing all individual model member trajectories.
forecast_days 1–16, default 7) with optional past_days (0–92)temperature_2m_member01, temperature_2m_member02, … Use the spread across members to compute exceedance probabilities, interquantile ranges, and decision thresholdsecmwf_ifs025 (51 members, global 0.25°), gfs025 (31 members), icon_seamless (40 members, global/Europe blend), gem_global (21 members). Omit models to use the API defaultmodel (system used) and member_count (number of members)hourly_variables or daily_variables is requiredCANVAS_PROVIDER_TYPE=duckdb — output includes canvas_id and truncated: true; query with openmeteo_dataframe_queryopenmeteo_get_floodGloFAS (Global Flood Awareness System) river discharge forecast and reanalysis via the Open-Meteo Flood API.
forecast_days for future outlook, start_date/end_date for historical analysis; both can be combinedriver_discharge (ensemble mean), river_discharge_mean, river_discharge_min, river_discharge_max, river_discharge_median, river_discharge_p25 (25th percentile), river_discharge_p75 (75th percentile) — all in m³/sBuilt on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1Open-Meteo–specific:
openmeteo_geocode resolves place names so agents don't need a separate geocoder*_units mapopenmeteo_get_historical and openmeteo_get_ensemble: large queries that exceed the inline record limit register a DuckDB dataframe for SQL queryingAgent-friendly output:
openmeteo_geocode returns the IANA timezone alongside coordinates — pass it directly as timezone to any weather toollatitude/longitude (Open-Meteo quantizes to the nearest model grid point) so agents can reason about grid alignmentdata_source: "CAMS" label on air quality results distinguishes modeled forecast data from measured station readingsA public instance is available at https://open-meteo.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"open-meteo-mcp-server": {
"type": "streamable-http",
"url": "https://open-meteo.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"open-meteo-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/open-meteo-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"open-meteo-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/open-meteo-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"open-meteo-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/open-meteo-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/open-meteo-mcp-server.git
cd open-meteo-mcp-server
bun install
All configuration is validated at startup via Zod schemas. No API key is required for non-commercial use — all variables are optional.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http | stdio |
MCP_HTTP_PORT | HTTP server port | 3010 |
MCP_HTTP_ENDPOINT_PATH | HTTP endpoint path | /mcp |
MCP_PUBLIC_URL | Public origin for TLS-terminating reverse-proxy deployments | — |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error) | info |
MCP_GC_PRESSURE_INTERVAL_MS | Opt-in forced-GC interval (ms, Bun only). Set to 60000 if heap growth is observed under sustained HTTP traffic. | 0 |
LOGS_DIR | Directory for log files (Node.js only) | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1 | in-memory |
CANVAS_PROVIDER_TYPE | Canvas engine for openmeteo_get_historical spillover: duckdb or none | none |
OPEN_METEO_API_BASE_URL | Override for the main forecast + elevation API | https://api.open-meteo.com |
OPEN_METEO_ARCHIVE_BASE_URL | Override for the ERA5 historical archive API | https://archive-api.open-meteo.com |
OPEN_METEO_MARINE_BASE_URL | Override for the marine forecast API | https://marine-api.open-meteo.com |
OPEN_METEO_AIR_QUALITY_BASE_URL | Override for the CAMS air quality API | https://air-quality-api.open-meteo.com |
OPEN_METEO_GEOCODING_BASE_URL | Override for the geocoding API | https://geocoding-api.open-meteo.com |
OTEL_ENABLED | Enable OpenTelemetry tracing and metrics | false |
See .env.example for the full list of optional overrides.
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
docker build -t open-meteo-mcp-server .
docker run --rm -p 3010:3010 open-meteo-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/open-meteo-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools, initializes the Open-Meteo service |
src/config | Server-specific environment variable parsing and validation with Zod |
src/mcp-server/tools/definitions | Tool definitions (*.tool.ts) — one file per tool; includes dataframe-describe.tool.ts and dataframe-query.tool.ts |
src/services/open-meteo | Open-Meteo HTTP client wrapping all six endpoints with retry, error classification, and columnar reshape |
src/services/canvas-accessor.ts | DataCanvas accessor for openmeteo_get_historical spillover |
tests/ | Unit and integration tests mirroring src/ |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagetools[] array in src/index.tsIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
Weather data by Open-Meteo.com — licensed CC BY 4.0.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
CANVAS_PROVIDER_TYPEdefault: noneCanvas engine for openmeteo_get_historical spillover. Set to 'duckdb' to enable DataCanvas and the dataframe_query / dataframe_describe tools. Default 'none' (spillover disabled).
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.