.codex-plugin — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited .codex-plugin (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<div align="center"> <h1>@cyanheads/open-meteo-mcp-server</h1> <p><b>Geocode places, fetch global weather forecasts, ERA5 historical climate, marine conditions, air quality, and terrain elevation via MCP. STDIO or Streamable HTTP.</b> <div>10 Tools</div> </p> </div>
<div align="center">
</div>
<div align="center">
</div>
<div align="center">
Public Hosted Server: https://open-meteo.caseyjhand.com/mcp
</div>
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/mcpgit clone https://github.com/cyanheads/open-meteo-mcp-server.gitcd open-meteo-mcp-serverbun installAll 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.
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suitedocker build -t open-meteo-mcp-server .
docker run --rm -p 3010:3010 open-meteo-mcp-serverThe 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 testApache-2.0 — see LICENSE for details.
Weather data by Open-Meteo.com — licensed CC BY 4.0.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.