mcp server
nws-weather-mcp-server
Get US weather forecasts, active alerts, and current observations via the National Weather Service API. STDIO or Streamable HTTP.
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- Node.js 20 or newer
{
"mcpServers": {
"nws-weather-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/nws-weather-mcp-server"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 17, 2026Public 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) 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 upstream- 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/effectiveLimit- Each
affectedZonesentry carries its zonetype(forecast/county/fire);referenceslists superseded messages newest first bysent; apointoutside NWS coverage fails withinvalid_point
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); 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, orSPS- Returns
productTextplusissuanceTime,issuingOffice,productName,productCode,wmoCollectiveId; an unknown office, or one with no current product of the requested type, fails withno_products - A product too large to inline (most ZFPs) returns an
outlineof its sections instead ofproductText; passsections(AFD section names, or zone codes for ZFP/HWO/SPS) to get the matching sections, and an unknown name fails withunknown_section
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###), fire, and unknown zone codes fail withzone_not_found; 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), 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. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"nws-weather-mcp-server": {
"type": "streamable-http",
"url": "https://nws.caseyjhand.com/mcp"
}
}
}
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.