WeatherOps MCP
Pulls Google Maps Platform weather data — hourly forecasts (forecast/hours), daily forecasts (forecast/days) and current conditions (currentConditions) — plus Google Geocoding v4 to turn a site address into coordinates, normalizing units to metric and evaluating per-hour threshold rules into GO/MARGINAL/NO-GO decisions with attribution.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@WeatherOps MCPCan we pour concrete at 35.7796,-78.6382 tomorrow 7am-3pm with concrete-pour profile?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
WeatherOps MCP
An MCP server and CLI for field-ops, event and construction go/no-go calls. Give it a site (address or lat/lng), a work window and a threshold profile; it pulls the Google Weather API hourly forecast (or the keyless US National Weather Service grid forecast) and returns every hour as GO, MARGINAL or NO-GO, with the exact rule that tripped and the value that tripped it.
Decision support only, not a safety authority. Forecasts can be wrong, and the four bundled profiles are illustrative examples, not safety standards. The responsible person on site, equipment manufacturer limits and applicable regulations decide whether work goes ahead.
The problem
Agents that plan crane lifts, concrete pours, roof work or outdoor events are asked "can we work tomorrow 07:00-17:00?" and answer from a weather summary. The useful answer is per hour, against the crew's own limits, with a reason a supervisor can check: "14:00 NO-GO, gusts 38 km/h break gust < 35". WeatherOps does the geocoding, paging, unit normalization and threshold evaluation in one read-only tool call.
Related MCP server: weather
Quickstart
bun install --frozen-lockfile
bun run demo # keyless: synthetic crane-lift window, prints the hour table below
bun run weatherops profiles
bun run weatherops go-no-go --lat 35.7796 --lng -78.6382 --profile crane-lift --start now --end +10h --source nws # live, keyless (US)
cp .env.example .env # add GOOGLE_MAPS_API_KEY for Google Weather + Geocoding
bun run weatherops go-no-go --address "..." --profile concrete-pour --start 2026-11-03T07:00:00-05:00 --end 2026-11-03T15:00:00-05:00 --fail-on no-goDemo output (reports/example-crane-lift.md, synthetic data), first rows:
Hour | Decision | Gust km/h | Temp C | Thunder % | Why |
10:00 | GO | 22 | 10 | 5 | |
11:00 | MARGINAL | 28 | 11 | 10 | thunderstorm_probability_pct 10% at 11:00 is within 10% of the 20% limit |
14:00 | NO-GO | 38 | 13 | 35 | wind_gust_kmh 38 km/h at 14:00 breaks gust: wind_gust_kmh < 35 margin 5 (+ thunder, storm-condition) |
MCP server
{
"mcpServers": {
"weatherops": {
"command": "bun",
"args": ["/abs/path/weatherops-mcp/src/cli.ts", "serve"],
"env": { "GOOGLE_MAPS_API_KEY": "" }
}
}
}Add "--fixtures" to args for the keyless synthetic demo. Five read-only tools:
Tool | Input | Upstream calls |
|
| 1 geocode (addresses only) + 1 per 24 forecast hours (Google), or 2 (NWS) |
| location, | 1 |
| location, optional profile/rules | 1 |
|
| 1 Geocoding v4 call |
| none | none |
Results come back as compact JSON plus Markdown (format: json|markdown|both). Every result carries disclaimer, the profile's own disclaimer, source.used / source.fallback, and the attribution lines Google requires.
Threshold profiles
A rule states what must hold for GO, e.g. wind_gust_kmh < 35:
violated: NO-GO (the rule "tripped"; the result names the rule, the value and the hour it came from)
holds, but within
marginof the limit: MARGINALthe source has no value for the metric:
on_missing(marginalby default, orno-go/ignore)horizon_hours: N(inlineover Nh) checks this hour and the next N-1, using the worst value (or the total withaggregate: sum). Read each hour as "start the job at this hour".
An hour's decision is the worst of its rules; the window's decision is the worst hour. The summary lists GO blocks, the first NO-GO hour and per-rule counts.
Bundled example profiles in profiles/ (each carries an "EXAMPLE ONLY, not a safety standard" disclaimer):
Profile | Rules |
|
|
|
|
|
|
|
|
Inline rules (CLI --rule, MCP rules[]) use METRIC OP VALUE [margin N] [over Nh] [sum] [missing marginal|no-go|ignore] [id NAME]; a rule with a profile rule's id replaces it. Metrics: temperature_c, feels_like_c, wind_speed_kmh, wind_gust_kmh, precip_probability_pct, precip_mm, thunderstorm_probability_pct, cloud_cover_pct, relative_humidity_pct, uv_index, visibility_km, ice_thickness_mm (numeric: < <= > >=), condition, precip_type (in / not_in). The CLI also takes --profile-file my.yaml; the MCP server only accepts bundled profile names.
Sources (checked against the references on 2026-10-21)
Source | Endpoint and parameters used | Fields read | Reference |
Google Weather hourly |
|
| |
Google Weather daily |
|
| |
Google Weather current |
|
| |
Google Geocoding v4 |
|
| |
NWS (keyless, US) |
| layers |
The Google key is sent only in the X-Goog-Api-Key header. Values are normalized to metric from the response's own unit fields (FAHRENHEIT, MILES_PER_HOUR, INCHES, WMO unit codes). source: auto uses Google when a key is set; on a missing key or any Google API error (for example 403 SERVICE_DISABLED) it falls back to NWS and says so in source.fallback. Outside NWS coverage /points answers 404, reported as NOT_COVERED.
Why the raw NWS grid instead of /gridpoints/{wfo}/{x},{y}/forecast/hourly: a live hourly response (Raleigh, 2026-10-21) had temperature, a text windSpeed ("6 mph"), probabilityOfPrecipitation, dewpoint and relativeHumidity per period, but no gust, thunder probability or precipitation amount. The raw grid has all three.
Measured
Produced by bun run report (scripts/report.ts): every row is a real call through the MCP server (in-memory client, real tools, service and HTTP client) with Google and NWS answered by the synthetic fixtures. No network, no keys. Source: reports/weatherops-mcp.md and .json. Run on 2026-10-21 (darwin-x64, Bun 1.4.3). "Upstream calls" includes the geocode call and any failed Google call before a fallback.
Scenario | Tool | Profile | Source used | Hours | GO | MARGINAL | NO-GO | First NO-GO (rule, value) | Longest GO block | Upstream calls |
harbor-yard crane lift 07-17 EST (Google) | go_no_go | crane-lift | 10 | 4 | 3 | 3 | 14:00 EST | 07:00 EST to 11:00 (4 h) | 2 | |
harbor-yard crane lift 07-17 EST, forced NWS grid | go_no_go | crane-lift | nws | 10 | 4 | 3 | 3 | 14:00 EST | 07:00 EST to 11:00 (4 h) | 3 |
harbor-yard roofing next day 07-17 EST (Google, 2 pages) | go_no_go | roofing | 10 | 5 | 1 | 4 | 07:00 EST | 12:00 EST to 17:00 (5 h) | 3 | |
river-lot concrete pour starts 07-15 MST (Google 403 -> NWS) | go_no_go | concrete-pour | nws (fallback: SERVICE_DISABLED) | 8 | 3 | 2 | 3 | 12:00 MST | 09:00 MST to 12:00 (3 h) | 3 |
coast-plaza outdoor event 08-22 GMT (Google; outside NWS) | go_no_go | outdoor-event | 14 | 11 | 2 | 1 | 19:00 GMT | 08:00 GMT to 18:00 (10 h) | 1 | |
harbor-yard inline rules (gust < 25 margin 5; rain < 2 mm over 3 h sum) | go_no_go | inline | 10 | 3 | 1 | 6 | 11:00 EST | 07:00 EST to 10:00 (3 h) | 2 | |
river-lot source=google only (403 SERVICE_DISABLED) | go_no_go | roofing | error: upstream_403 SERVICE_DISABLED | - | - | - | - | - | - | |
coast-plaza source=nws only (outside coverage) | go_no_go | outdoor-event | nws | error: upstream_404 NOT_COVERED | - | - | - | - | - | - |
harbor-yard 10-day outlook (5 days x day/night) | outlook | crane-lift | 10 parts | 1 | 2 | 7 | - | - | 2 | |
harbor-yard current conditions vs crane-lift | current_conditions | crane-lift | now | 1 | 0 | 0 | - | - | 2 |
Google vs NWS on the same synthetic weather (harbor-yard crane-lift 07-17 EST): 10 of 10 hours get the same decision. The storm-condition rule tripped 0 NO-GO hours on NWS (no condition type in the grid, rule set to on_missing: ignore) vs 2 on Google.
Example outputs: crane lift, concrete pour with NWS fallback, outdoor event, 10-day outlook.
Live checks (bun run test:live, 2026-10-21, this machine)
Check | Result |
Google Weather | HTTP 403 |
Geocoding v4 | HTTP 200, |
NWS | 13 hours evaluated from grid |
NWS | 404 -> |
| fell back to NWS with |
Without a key the Google and Geocoding tests print skipped: no GOOGLE_MAPS_API_KEY; with WEATHEROPS_LIVE=0 (CI) every live test prints skipped: WEATHEROPS_LIVE=0.
Limits
Not verified live: Google Weather responses. The Weather API is not enabled in the only project available to this build, so the Google client has been exercised only against synthetic fixtures built from the published reference and example response. Field names and unit enums (
CELSIUS/FAHRENHEIT,KILOMETERS_PER_HOUR/MILES_PER_HOUR,MILLIMETERS/INCHES,KILOMETERS/MILES) come from the reference pages linked above; how real responses fill optional fields (for example whetherwind.gustorqpfcan be absent) is not confirmed.The forecast does not say at what height wind and gusts apply. Crane and work-at-height limits normally refer to wind at height; treat forecast wind as a lower bound.
NWS fallback: no condition type, precipitation type or UV; precipitation and ice amounts arrive as 6 h blocks and are spread evenly over each hour; values are resampled from the raw grid, not the NWS hourly text forecast. US only.
The
outlooktool is coarse: Google day parts report max wind/gust and average thunderstorm probability for 12 h, and only the day's max/min temperature, so a cold night also flags the daytime part for a lower temperature limit.current_conditionsis Google only (NWS observations are not wired in).No caching; every call goes upstream. A per-session call budget (
WEATHEROPS_MAX_CALLS, default 60) protects billed keys.Work windows are limited to 72 h and must end inside the 240 h hourly forecast (plus any rule horizon).
The four profiles are examples written for this lab. They are not derived from any standard, manufacturer chart or regulation.
Development
bun run check is the local gate (and the only CI step): frozen install, skills layout, strict YAML (workflow + profiles), Biome, tsc --noEmit, unit + keyless e2e tests, live tests (skip cleanly), the report, and gitleaks dir. Fixtures are regenerated with bun run fixtures.
Not affiliated
Not affiliated with, endorsed by, or sponsored by Google LLC or the US National Weather Service. Google Maps and Google Maps Platform are trademarks of Google LLC. Google-sourced results print "Source: Includes weather data from Google" and "Includes data from Google Maps" as the Weather API policies require.
Built by SkilledDragon LLC. Questions: hello@skilleddragon.com. Apache-2.0, see LICENSE and NOTICE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Forecasts for any US point, with context: alerts, what changed overnight, why, and history.
Visual Crossing Weather MCP — wraps the Visual Crossing Weather Timeline API
Multi-model weather forecasts: point series, model scoreboard, and gridded fields. No auth.
Weather history, nowcasts, forecasts, and soil data for saved locations or any US or Canada point.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceWeather files (EPW/DDY) for building energy simulation, on-demand. Four tools: search the 17,000-station catalog, analyze any EPW (design conditions, HDD/CDD, DesignDay IDF emit), render 5 chart types (diurnal, wind rose, temp carpet, monthly box plot, comparison), and generate TMY/AMY/CMIP6-morphed scenarios with UHI, extreme events, and wildfire smoke overlays. 3 of 4 tools work without API key.MIT
- FlicenseNot gradedqualityDmaintenanceProvides weather forecasts, current conditions, and alerts for US locations using the National Weather Service API.1-
- AlicenseNot gradedqualityAmaintenanceGeocode places, fetch global weather forecasts, ERA5 historical climate, marine conditions, air quality, and terrain elevation via MCP. Provides 11 tools over STDIO or Streamable HTTP.210 npm10Apache 2.0
- AlicenseNot gradedqualityCmaintenanceEnables users to check whether an Australian field-service job can be worked at a location on a given day for a specific trade, using live weather forecasts, daylight hours, and public holiday data.MIT