
Connects Claude directly to the National Weather Service API with zero authentication required. You get seven tools covering the essentials: 7-day and hourly forecasts by coordinates, active alert searches with filtering by severity and event type, current observations from nearby stations, and narrative products like Area Forecast Discussions from any Weather Forecast Office. The coordinate-to-grid resolution happens automatically with caching, and observations come back in dual units. Useful when you need authoritative US weather data without managing API keys or parsing raw NOAA feeds. Available as a public hosted instance at nws.caseyjhand.com/mcp or self-hosted via npm.
Public tool metadata for what this MCP can expose to an agent.
nws_get_forecastGet the weather forecast for a US location. Returns either named 12-hour periods (default) or hourly breakdowns. Internally resolves coordinates to the NWS grid.3 paramsGet the weather forecast for a US location. Returns either named 12-hour periods (default) or hourly breakdowns. Internally resolves coordinates to the NWS grid.
hourlybooleanlatitudenumberlongitudenumbernws_search_alertsSearch active weather alerts (watches, warnings, advisories) across the US. Filter by state, coordinates, zone, event type, severity, urgency, or certainty. area, point, and zone are mutually exclusive. Omit all filters for a national search.8 paramsSearch active weather alerts (watches, warnings, advisories) across the US. Filter by state, coordinates, zone, event type, severity, urgency, or certainty. area, point, and zone are mutually exclusive. Omit all filters for a national search.
areastringcertaintyarrayeventarraypointstringseverityarraystatusstringActual · Exercise · System · Test · Draftdefault: Actualurgencyarrayzonestringnws_get_observationsGet current weather observations (actual measured conditions). Accepts coordinates (resolves nearest station automatically) or a station ID directly (e.g., "KSEA").3 paramsGet current weather observations (actual measured conditions). Accepts coordinates (resolves nearest station automatically) or a station ID directly (e.g., "KSEA").
latitudenumberlongitudenumberstation_idstringnws_find_stationsFind weather observation stations near a location. Returns stations sorted by proximity with distance and bearing. Use to discover station IDs for nws_get_observations.3 paramsFind weather observation stations near a location. Returns stations sorted by proximity with distance and bearing. Use to discover station IDs for nws_get_observations.
latitudenumberlimitintegerlongitudenumbernws_list_alert_typesList all valid NWS alert event type names. Use to discover valid values for the event filter in nws_search_alerts, or to browse alert categories. No parameters required.List all valid NWS alert event type names. Use to discover valid values for the event filter in nws_search_alerts, or to browse alert categories. No parameters required.
No parameter schema in public metadata yet.
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
US weather data from the National Weather Service API (api.weather.gov). Get forecasts, active alerts, current observations, forecast-office narrative products, and zone-level text forecasts for any coordinate in the 50 states and US territories, plus national alert counts and a station's last ~7 days of observations. Adjacent marine areas are covered by alerts, plus stations and observations near the coast; NWS publishes no point forecast for them, and zone text forecasts for marine zones vary by zone. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| 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. |
| 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.
nws_get_forecast toollatitude + longitude; returns named 12-hour periods by default (14, ~7 days), or with hourly: true one-hour periods (named by weekday and start time in the location's time zone, e.g. Fri 6:00 AM) with dewpoint and humidity, 48 per page of the ~156 upstreamforecastZone and county zone codes for chaining into nws_search_alerts; marine coordinates fail with a typed marine_forecast_unsupported error pointing to a nearby land point or nws_search_alerts, and land points NWS serves no forecast grid for with no_forecast_gridnws_search_alerts toolarea, point, zone, region_type, or region — or none for a national search; event matches case-insensitively and partially; status defaults to Actual (also Exercise, System, Test, Draft); limit (default 25) pages at most 25 alerts, and a larger limit is served as 25 and reported through requestedLimit/effectiveLimitaffectedZones entry carries its zone type (forecast/county/fire), marking which codes chain into nws_get_zone_forecast; CAP message-lifecycle fields (sent, effective, status, messageType, references) are distinct from the hazard's own onset/ends; references lists superseded messages newest first by sentpoint outside NWS coverage fails with invalid_pointnws_get_alert toolalert_id: an alert id from nws_search_alerts, or a references[].identifier from any alert; returns { alert } in the same shape nws_search_alerts returns, including superseded messages that an active-alert search no longer listsreferences run newest first, so the references sharing the newest sent are its immediate predecessors (references[0] is one; an update can merge several earlier segments) and a revision chain is walked one call per messagealert_not_found errornws_get_alert_counts tooltotalAlerts (landAlerts + marineAlerts), plus areas counts keyed by state/territory or marine area code and regions counts keyed by marine region (AL, AT, GL, GM, PA, PI), each listing only codes with an active alerttotalAlerts can exceed a national nws_search_alerts totalCount (status: Actual by default); an alert counts once in each area its zones fall in, so areas can sum past totalAlertsnws_get_observations toolstation_id directlynws_get_observation_history toolstation_id (from nws_find_stations); optional start (inclusive) and end (exclusive) as ISO 8601 date-times with seconds and an offset; limit (default 24) pages at most 100 observations, and a larger limit is served as 100 and reported through requestedLimit/effectiveLimit; newest first, back through the ~7 days NWS keepsnws_get_observations measurement fields, null where the station reported nothing; an unknown station fails with station_not_found, and a malformed window or a start not before end with invalid_time_windownextCursor appears only when older observations remain in the window (a window holding exactly limit ends with no cursor), and pages neither repeat nor skip an observation; no totalCount, since NWS reports none for a windownws_find_stations toollatitude + longitude; optional limit (default 10) sizes the page, at most 50 stations; a larger limit is served as 50 and reported through requestedLimit/effectiveLimitnws_get_observations, distance (km), bearing, zone codes, elevation, and time zonenws_list_alert_types toolevent filter in nws_search_alertsnws_get_office_discussion tooloffice: product location code of 2–3 letters or digits, usually the 3-letter WFO code (e.g., "SEW" for Seattle) returned as the office field by nws_get_forecast; Anchorage files its ZFP under AER and ALU rather than AFC, San Juan its ZFP under PR, and Guam its SPS under PQ1; product_type: AFD (default), HWO, ZFP, or SPSproductText plus issuanceTime, issuingOffice, productName, productCode, wmoCollectiveId; an unknown office, or a valid office with no current product of the requested type, fails with a typed no_products error (SPS and HWO are episodic; for AFD and ZFP the recovery names the location-code case)outline of its sections (name, area label, size) instead of productText; optional sections (AFD section names, or zone codes for ZFP/HWO/SPS) returns the product header, the matching sections verbatim, and the product's closing lines on a product of any size, and a name the product lacks fails with unknown_section. A notice names the worked re-callnws_get_zone_forecast toolzone_id: forecast zone code (e.g., "WAZ315") — returned by nws_get_forecast (forecastZone), nws_find_stations (forecastZone column), and nws_search_alerts (the code of an affectedZones entry with type: "forecast")XXC###), fire, and unknown zone codes fail with a typed zone_not_found error, marine zones NWS publishes no text forecast for (offshore zones such as GMZ056, and some coastal zones such as LMZ645) with marine_forecast_unsupported (many coastal zones, e.g. PZZ251, return periods), and a valid land zone NWS publishes no text forecast for with zone_forecast_unavailable, which carries a point inside the zone for nws_get_forecastnws://alert-types resourceapplication/jsonBuilt 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:
User-Agent header automatically (configurable via NWS_USER_AGENT) — NWS returns 403 without one/points, cached for 1h since grid cells rarely changenws_get_forecast, nws_find_stations, and nws_search_alerts report totalCount against this page's shown, and nws_get_observation_history reports shown alone (NWS gives no total for a time window); pass the returned nextCursor back as cursor for the next page (omitted on the last page)Agent-friendly output:
nws_get_office_discussion, nws_get_zone_forecast, and nws_search_alerts without re-deriving themnotice naming the cause and the concrete next step, rather than an empty array or a bare pagetype (forecast/county/fire), CAP status/messageType distinct from hazard onset/ends, and typed error reasons (invalid_area_code, no_products, zone_not_found, …) — callers branch on data, not string parsingformat() renders, so structured and text output agreeA 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"
}
}
}
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
git clone https://github.com/cyanheads/nws-weather-mcp-server.git
cd nws-weather-mcp-server
bun install
| 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.
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
| 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/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for domain-specific logging, ctx.state for storagecreateApp() arrays in src/index.tsIssues are welcome. Run checks before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
NWS_USER_AGENTdefault: (nws-weather-mcp-server, github.com/cyanheads/nws-weather-mcp-server)User-Agent header for NWS API requests. The API requires this header but a default is provided.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
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'.