About nws-weather-mcp-server
nws-weather-mcp-server provides forecasts, live observations, and alerts from the US National Weather Service API for workflows that need US weather data. It also covers station history, zone forecasts, and forecast office discussions, with no API key required.
Key features
- 01Get seven-day or hourly forecasts
- 02Filter alerts by area and event
- 03Query current conditions and station history
- 04Find nearby observation stations
- 05Retrieve zone forecasts and office discussions
Use cases
- 01Check a forecast for specific coordinates
- 02Filter active alerts by state, area, or event
- 03Review recent observations from a station
MCP support
As an MCP server, it exposes tools for US National Weather Service forecasts, alerts, observations, stations, and office discussions, plus a resource listing alert event types. It supports STDIO and Streamable HTTP.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://nws.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-nws-weather https://nws.caseyjhand.com/mcp{"mcpServers":{"cyanheads-nws-weather":{"type":"http","url":"https://nws.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-nws-weather":{"type":"http","url":"https://nws.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-nws-weather":{"type":"http","url":"https://nws.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-nws-weather":{"serverUrl":"https://nws.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
10| Parameter | Type | Required | Description |
|---|---|---|---|
| cursor | string | No | Opaque continuation token from a previous response's nextCursor, to retrieve the next 48 periods. Omit for the first page. Every call re-fetches the forecast, so consecutive periods are contiguous within one response; NWS reissues forecasts through the day, so a later call can window a regenerated period array. |
| hourly | boolean | No | If true, returns hourly forecast (48 one-hour periods per page, ~156 available) instead of 12-hour named periods (14 periods). Hourly includes dewpoint and relative humidity. |
| latitude | number | Yes | Latitude in decimal degrees (e.g., 47.6062). |
| longitude | number | Yes | Longitude in decimal degrees (e.g., -122.3321). |
Details
From the project README@cyanheads/nws-weather-mcp-server
Get US weather forecasts, active alerts, and current observations via the National Weather Service API. STDIO or Streamable HTTP.
Public Hosted Server: https://nws.caseyjhand.com/mcp
Overview
Real-time US weather from the National Weather Service: forecasts, active alerts, current conditions, and forecaster discussions for any point in the 50 states and US territories, plus zone forecasts, coastal and marine alerts, and a week of station history. No API key required.
Tools
| Tool | Description |
|---|---|
nws_get_forecast | 7-day or hourly forecast for coordinates. Resolves NWS grid internally. |
nws_search_alerts | Active weather alerts filtered by area, point, zone, event, severity, urgency, certainty, and status. |
nws_get_alert | One alert message by ID, current or superseded (~7-day retention). |
nws_get_alert_counts | Active alert counts nationwide, per state/territory or marine area, and per marine region. |
nws_get_observations | Current conditions by coordinates (nearest station) or station ID. |
nws_get_observation_history | A station's recent observations, newest first, paged back through the ~7 days NWS keeps. |
nws_find_stations | Nearby observation stations sorted by distance with bearing. |
nws_list_alert_types | All valid alert event type names for filter discovery. |
nws_get_office_discussion | Latest narrative product (AFD, HWO, ZFP, SPS, FWF) from a Weather Forecast Office; a product too large to inline comes back as a section outline. |
nws_get_zone_forecast | Text forecast periods for an NWS forecast zone. |
Resources
| Resource | Description |
|---|---|
nws://alert-types | Static list of all valid NWS alert event type names. |
Also reachable via the nws_list_alert_types tool, for MCP clients that don't support resources.
Capability reference
nws_get_forecast tool
latitude+longitude; returns 14 named 12-hour periods (~7 days) by default, or withhourly: trueone-hour periods with dewpoint and humidity, 48 per page of the ~156 upstreamnextCursorcarries its mode, so an hourly walk continues hourly without resendinghourly: trueinclude_amounts: trueadds every nativequantitativePrecipitation,snowfallAmount, andiceAccumulationinterval asprecipitationAmounts(layer,uom,valueswithvalidTimeandvalue), plus the separateamountsUpdateTime. Default false; resend it on any cursor page that needs amounts. Interval strings, units, zeroes, and nulls stay unchanged. Missing layers and unavailable amounts are explained innotice; present empty layers carryvalues: []. Absent units or update time are null. An unavailable amount feed leaves the main forecast available.- Returns
updateTime, when the grid's forecast data was last updated, besidegeneratedAt; anoticeflags a grid not updated in more than 24 hours - Returns the
forecastZoneandcountyzone codes for chaining intonws_search_alerts - Marine coordinates fail with
marine_forecast_unsupported, and land points NWS serves no forecast grid for fail withno_forecast_grid
nws_search_alerts tool
- At most one location filter (
area,point,zone,region_type, orregion), or none for a national search;eventmatches case-insensitively and partially;statusdefaults toActual(alsoExercise,System,Test,Draft) limit(default 25) is capped at 25; a larger limit is served as 25 and reported throughrequestedLimit/effectiveLimitnextCursorcarries the query's filters and page size, so pass it back ascursoron its own; filters sent with it are ignored- Each
affectedZonesentry carries its zonetype(forecast/county/fire);referenceslists superseded messages newest first bysent; apointoutside NWS coverage fails withinvalid_point - Each alert carries
office(the issuing office code fornws_get_office_discussion, e.g.RIW), rawvtecstrings, thenwsHeadline, andhazardtags such asmaxHailSizeandmaxWindGust, verbatim
nws_get_alert tool
alert_id: an alertidfromnws_search_alerts, or areferences[].identifierfrom any alert; returns{ alert }in the same shape asnws_search_alerts, including superseded messages- A malformed ID, an unknown one, and one past NWS's ~7-day retention all fail with
alert_not_found
nws_get_alert_counts tool
- No input; returns national
totalAlerts(landAlerts+marineAlerts), plusareascounts keyed by state/territory or marine area code andregionscounts keyed by marine region (AL,AT,GL,GM,PA,PI), each listing only codes with an active alert - Counts cover every message status, Test and Exercise included, so
totalAlertscan exceed a nationalnws_search_alertstotalCount(status: Actualby default); an alert counts once in each area its zones fall in, soareascan sum pasttotalAlerts
nws_get_observations tool
- Look up by coordinates (resolves nearest station) or
station_iddirectly - Dual-unit display on every measurement (F/C, mph/km/h, inHg/hPa, mi/km, in/mm), temperatures to one decimal; 1-, 3-, and 6-hour precipitation amounts from hourly reports, with
0a trace andnullno amount reported; observations older than 2 hours carry a staleness notice, and a separate warning flags a station with most measurements unavailable
nws_get_observation_history tool
station_id(fromnws_find_stations); optionalstart(inclusive) andend(exclusive) as ISO 8601 date-times with seconds and an offset; newest first, back through the ~7 days NWS keepslimit(default 24) is capped at 100; a larger limit is served as 100 and reported throughrequestedLimit/effectiveLimit- Each observation carries the
nws_get_observationsmeasurement fields,nullwhere the station reported nothing; an unknown station fails withstation_not_found, and a malformed window or astartnot beforeendwithinvalid_time_window nextCursorappears only when older observations remain; there is nototalCount, since NWS reports none for a window
nws_find_stations tool
latitude+longitude; optionallimit(default 10) is capped at 50; a larger limit is served as 50 and reported throughrequestedLimit/effectiveLimit- Nearest first; each result carries the station ID for
nws_get_observations, distance (km), bearing, zone codes, elevation, and time zone
nws_list_alert_types tool
- Returns the full set of event types the NWS API recognizes (e.g., "Tornado Warning", "Heat Advisory")
- Use to discover valid values for the
eventfilter innws_search_alerts
nws_get_office_discussion tool
office: usually the 3-letter WFO code (e.g., "SEW" for Seattle) returned as theofficefield bynws_get_forecast;product_type:AFD(default),HWO,ZFP,SPS, orFWF(Fire Weather Planning Forecast)- Returns
productTextplusissuanceTime,issuingOffice,productName,productCode,wmoCollectiveId;content[]carries the product text in atextcode block, so fixed-width tables keep their columns; an unknown office, or one with no current product of the requested type, fails withno_products - A product too large to inline (most ZFPs and FWFs) returns an
outlineof its sections instead ofproductText; passsections(AFD section names, or zone codes for ZFP/HWO/SPS/FWF) to get the matching sections, and an unknown name fails withunknown_section - An alert zone typed
firegets its forecast from the FWF:officefrom the alert'sofficefield,product_type: "FWF",sections: [<zone code>]
nws_get_zone_forecast tool
zone_id: forecast zone code (e.g., "WAZ315") — returned bynws_get_forecast(forecastZone),nws_find_stations(forecastZonecolumn), andnws_search_alerts(thecodeof anaffectedZonesentry withtype: "forecast")- Returns named periods (e.g., "Today", "Tonight", "Monday") with narrative text from local forecasters
- County (
XXC###) and unknown zone codes fail withzone_not_found, and so do most fire zone codes, whose forecast is their segment of the office FWF onnws_get_office_discussion; a fire code that is also a public zone code returns the public zone's forecast; marine zones with no text forecast fail withmarine_forecast_unsupported, and land zones with none withzone_forecast_unavailable
nws://alert-types resource
- Static list of all valid NWS alert event type names, returned as
application/json - No parameters; cached publicly for 1 hour
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
NWS-specific:
- Sends the required
User-Agentheader automatically (configurable viaNWS_USER_AGENT) — NWS returns 403 without one - Automatic coordinate-to-grid resolution via
/points, cached for 1h since grid cells rarely change - Request timeouts plus retry/backoff for transient NWS API failures
- Zero-auth access — no API keys required
- Paged results — pass the returned
nextCursorback ascursorfor the next page (omitted on the last page)
Agent-friendly output:
- Provenance — responses echo office codes, time zones, and zone codes so agents can chain into
nws_get_office_discussion,nws_get_zone_forecast, andnws_search_alerts - Guidance over silence — empty, truncated, or cursor-past-end results carry a
noticenaming the cause and the next step - Typed error reasons (
invalid_area_code,no_products,zone_not_found, …) so callers branch on data, not string parsing - Dual-unit measurements (F/C, mph/km/h, inHg/hPa, mi/km, in/mm), rounded to match the text output
Getting started
Public Hosted Instance
A public instance is available at https://nws.caseyjhand.com/mcp — no installation required. It serves Streamable HTTP; each client takes its own config shape.
For Claude Code:
claude mcp add --transport http nws-weather-mcp-server https://nws.caseyjhand.com/mcp
For Cline (cline_mcp_settings.json):
{
"mcpServers": {
"nws-weather-mcp-server": {
"type": "streamableHttp",
"url": "https://nws.caseyjhand.com/mcp"
}
}
}
For Cursor (mcp.json):
{
"mcpServers": {
"nws-weather-mcp-server": {
"url": "https://nws.caseyjhand.com/mcp"
}
}
}
Claude Desktop adds remote servers under Settings → Connectors.
Self-Hosted / Local
Add the following to your MCP client configuration file.
{
"mcpServers": {
"nws-weather-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/nws-weather-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"nws-weather-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/nws-weather-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"nws-weather-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/nws-weather-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_SESSION_MODE=stateless MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
Installation
- Clone the repository:
git clone https://github.com/cyanheads/nws-weather-mcp-server.git
- Navigate into the directory:
cd nws-weather-mcp-server
- Install dependencies:
bun install
Configuration
| Variable | Description | Default |
|---|---|---|
NWS_USER_AGENT | User-Agent for NWS API requests. The API requires this header. | (nws-weather-mcp-server, ...) |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_HTTP_HOST | Hostname for HTTP server. | 127.0.0.1 |
MCP_SESSION_MODE | HTTP session mode: stateful, stateless, or auto. | stateless |
MCP_LOG_LEVEL | Log level: debug, info, notice, warning, error. | info |
See .env.example for the full list including auth, storage, and OpenTelemetry options.
Running the server
Local development
-
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 # Lints, formats, type-checks bun run test # Runs test suite
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and the resource. |
src/mcp-server/tools/definitions/ | Tool definitions (*.tool.ts). |
src/mcp-server/resources/definitions/ | Resource definitions (*.resource.ts). |
src/services/nws/ | NWS API client and response types. |
src/config/ | Environment variable parsing and validation with Zod. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor domain-specific logging,ctx.statefor storage - Add new tools/resources to the barrel exports and the
createApp()arrays insrc/index.ts - Wrap NWS API calls: validate raw JSON → normalize to domain types → return the output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.