nws-weather-mcp-server
An MCP server that provides access to National Weather Service data, including 7-day or hourly forecasts, active weather alerts, current observations, and station history for US locations and territories.
Endpoint and access
No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.
https://nws.caseyjhand.com/mcpWhat its tools do
10 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.
Checks and signals
Each line is separate evidence, not a trust score.
- Passed Endpoint answered the live check ·
- Availability 1 of 1 checks passed in 30 days
What you can do with it
- Get weather forecasts for specific coordinates
- Search for active weather alerts by state or zone
- Retrieve current weather observations from nearby stations
- List valid alert types for filtering
Source and maintenance
- Maintenance checked
Protocol and capabilities
- Server
- nws-weather-mcp-server 0.12.0
- MCP protocol negotiated in check
- 2025-11-25
- Tools
- 10 advertised
- Resources
- 2 advertised
- Resource templates
- 1 advertised
- Prompts
- 0 advertised
{
"tools": {
"listChanged": true
},
"logging": {},
"prompts": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"extensions": {
"io.modelcontextprotocol/skills": {
"directoryRead": true
}
}
}Server-provided instructions
Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.
Tools
10 advertised
nws_get_forecast — Nws Get Forecast
Get the weather forecast for a US location. Returns either named 12-hour periods (default) or hourly breakdowns.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"latitude",
"longitude"
],
"properties": {
"cursor": {
"type": "string",
"description": "Opaque continuation token from a previous response's nextCursor, to retrieve the next 48 periods. Omit for the first page. The token carries the mode it was issued in (hourly or 7-day), so the next page stays in that mode whatever hourly is set to. 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": {
"type": "boolean",
"default": false,
"description": "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. Sets the mode of the first page; a cursor carries its own mode, so this is ignored when cursor is set."
},
"latitude": {
"type": "number",
"maximum": 90,
"minimum": -90,
"description": "Latitude in decimal degrees (e.g., 47.6062)."
},
"longitude": {
"type": "number",
"maximum": 180,
"minimum": -180,
"description": "Longitude in decimal degrees (e.g., -122.3321)."
},
"include_amounts": {
"type": "boolean",
"default": false,
"description": "Include every native quantitativePrecipitation, snowfallAmount, and iceAccumulation interval from the NWS grid. Applies to this call only, including cursor pages; units and interval strings remain as NWS sends them. Unavailable amounts are explained in notice while the forecast remains available."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"location",
"generatedAt",
"updateTime",
"periods",
"totalCount",
"shown",
"mode"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"mode": {
"type": "string",
"description": "Forecast mode: \"hourly\" or \"7-day\""
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"out_of_scope",
"marine_forecast_unsupported",
"no_forecast_grid"
],
"description": "Machine-readable failure mode. Declared by this tool: `out_of_scope`: Coordinates fall outside US National Weather Service coverage. `marine_forecast_unsupported`: Coordinates fall in a marine area, where NWS publishes no point forecast. `no_forecast_grid`: Coordinates are on land in a forecast zone NWS serves no forecast grid for (e.g., interior Northern Mariana Islands). Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"shown": {
"type": "number",
"description": "Number of forecast periods in this page (at most 48)."
},
"notice": {
"type": "string",
"description": "Guidance when forecast data was last updated more than 24 hours ago, periods remain or the cursor points past the end, or requested amount data or layers are unavailable."
},
"periods": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"startTime",
"endTime",
"temperature",
"temperatureUnit",
"windSpeed",
"windDirection",
"shortForecast",
"detailedForecast",
"precipChancePct",
"dewpointC",
"relativeHumidityPct"
],
"properties": {
"name": {
"type": "string",
"description": "Period name (e.g., \"Today\", \"Tonight\"); in hourly mode, the weekday and start time in the location time zone (e.g., \"Fri 6:00 AM\")"
},
"endTime": {
"type": "string",
"description": "Period end (ISO 8601)"
},
"dewpointC": {
"type": [
"number",
"null"
],
"description": "Dewpoint in Celsius (hourly only)"
},
"startTime": {
"type": "string",
"description": "Period start (ISO 8601)"
},
"windSpeed": {
"type": "string",
"description": "Wind speed (e.g., \"10 mph\")"
},
"temperature": {
"type": "number",
"description": "Temperature value"
},
"shortForecast": {
"type": "string",
"description": "Brief forecast (e.g., \"Mostly Sunny\")"
},
"windDirection": {
"type": "string",
"description": "Wind direction (e.g., \"NW\")"
},
"precipChancePct": {
"type": [
"number",
"null"
],
"description": "Probability of precipitation in percent (0-100)"
},
"temperatureUnit": {
"type": "string",
"description": "Temperature unit (F or C)"
},
"detailedForecast": {
"type": "string",
"description": "Full narrative forecast"
},
"relativeHumidityPct": {
"type": [
"number",
"null"
],
"description": "Relative humidity in percent (0-100, hourly only)"
}
},
"description": "Single forecast period with time range, conditions, and narrative",
"additionalProperties": false
},
"description": "Forecast periods"
},
"location": {
"type": "object",
"required": [
"city",
"state",
"office",
"timeZone",
"forecastZone",
"county"
],
"properties": {
"city": {
"type": "string",
"description": "City name"
},
"state": {
"type": "string",
"description": "State name"
},
"county": {
"type": "string",
"description": "County zone code for chaining to nws_search_alerts"
},
"office": {
"type": "string",
"description": "NWS Weather Forecast Office code"
},
"timeZone": {
"type": "string",
"description": "IANA time zone"
},
"forecastZone": {
"type": "string",
"description": "Forecast zone code for chaining to nws_search_alerts"
}
},
"description": "Resolved location metadata",
"additionalProperties": false
},
"nextCursor": {
"type": "string",
"description": "Opaque token for the next page of periods — pass it back as `cursor`; it carries this forecast mode (hourly or 7-day). Omitted when this is the last page."
},
"totalCount": {
"type": "number",
"description": "Total forecast periods available upstream before the page window was applied — NOT the number in this page, which is shown. Compare it against shown to tell whether periods were withheld."
},
"updateTime": {
"type": [
"string",
"null"
],
"description": "When the data this forecast was generated from was last updated (ISO 8601, as NWS sends it). A grid that stops updating keeps this time while generatedAt keeps advancing. Null when NWS omits it."
},
"generatedAt": {
"type": "string",
"description": "When NWS generated this response (ISO 8601). It advances whenever NWS regenerates the response, even when the underlying data is unchanged; see updateTime for the data age."
},
"amountsUpdateTime": {
"type": [
"string",
"null"
],
"description": "Native grid updateTime, distinct from forecast updateTime; null when omitted upstream and absent when amounts were not fetched"
},
"precipitationAmounts": {
"type": "array",
"items": {
"type": "object",
"required": [
"layer",
"uom",
"values"
],
"properties": {
"uom": {
"type": [
"string",
"null"
],
"description": "Native NWS layer unit, or null when omitted"
},
"layer": {
"enum": [
"quantitativePrecipitation",
"snowfallAmount",
"iceAccumulation"
],
"type": "string",
"description": "Native grid amount layer name"
},
"values": {
"type": "array",
"items": {
"type": "object",
"required": [
"validTime",
"value"
],
"properties": {
"value": {
"type": [
"number",
"null"
],
"description": "Native amount, or null when unreported"
},
"validTime": {
"type": "string",
"description": "Native ISO 8601 interval string, unchanged"
}
},
"description": "One native accumulation interval",
"additionalProperties": false
},
"description": "Every interval in this layer, including null measurements; empty when NWS publishes no intervals"
}
},
"description": "One present quantitative amount layer",
"additionalProperties": false
},
"description": "Present grid amount layers when requested and fetched successfully; missing layers are named in notice"
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_search_alerts — Nws Search Alerts
Search active weather alerts (watches, warnings, advisories) across the US. Filter by state, coordinates, zone, land/marine region, event type, severity, urgency, or certainty. area, point, zone, region_type, and region are mutually exclusive — provide at most one. Omit all filters for a national search.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"area": {
"type": "string",
"pattern": "^\\s*(?:[A-Za-z]{2}\\s*)?$",
"description": "US state/territory code (e.g., \"WA\", \"OK\", \"PR\") or marine area code (e.g., \"GM\"). Mutually exclusive with point and zone."
},
"zone": {
"type": "string",
"pattern": "^\\s*(?:[A-Za-z]{2}[CcZz]\\d{3}\\s*)?$",
"description": "NWS forecast zone (e.g., \"WAZ558\") or county zone (e.g., \"WAC033\"). Mutually exclusive with area and point."
},
"event": {
"type": "array",
"items": {
"type": "string"
},
"description": "Filter to specific event types (e.g., [\"Tornado Warning\"]). Matches are case-insensitive and partial, so \"tornado\" matches both \"Tornado Warning\" and \"Tornado Watch\". Use nws_list_alert_types to discover valid names."
},
"limit": {
"type": "integer",
"default": 25,
"maximum": 10000,
"minimum": 1,
"description": "Maximum number of alerts to include in this page (default 25). A page holds at most 25; a larger limit (up to 10000) is served as 25 and reported through requestedLimit and effectiveLimit. totalCount still reports the full number of distinct matches, so a small limit returns a digest of broad or national searches without dropping the total; pass the returned nextCursor as cursor to reach the rest."
},
"point": {
"type": "string",
"pattern": "^\\s*(?:(?:-\\s*)?\\d(?:\\s*\\d)*(?:\\s*\\.\\s*\\d(?:\\s*\\d)*)?\\s*,\\s*(?:-\\s*)?\\d(?:\\s*\\d)*(?:\\s*\\.\\s*\\d(?:\\s*\\d)*)?\\s*)?$",
"description": "Coordinates as \"lat,lon\" (e.g., \"47.6,-122.3\"). Returns alerts whose geometry contains this point. Mutually exclusive with area and zone."
},
"cursor": {
"type": "string",
"description": "Opaque continuation token from a previous response's nextCursor; send it on its own. Omit for the first page. It carries that query's filters and page size, so the filter inputs and limit apply to the first page only. Every call re-fetches the active-alert feed, so alerts are contiguous within one response but not across calls — the active set changes continuously as alerts are issued and expire, so a continued page covers the collection as it stands at that moment."
},
"region": {
"type": "array",
"items": {
"enum": [
"AL",
"AT",
"GL",
"GM",
"PA",
"PI"
],
"type": "string"
},
"description": "Restrict to NWS marine region groups: \"AL\" (Alaska waters), \"AT\" (Atlantic Ocean), \"GL\" (Great Lakes), \"GM\" (Gulf of Mexico), \"PA\" (Eastern Pacific and US West Coast), \"PI\" (Central and Western Pacific). Marine alerts only — a land alert never matches. Mutually exclusive with area, point, zone, and region_type."
},
"status": {
"enum": [
"Actual",
"Exercise",
"System",
"Test",
"Draft"
],
"type": "string",
"default": "Actual",
"description": "Alert status filter. Default \"Actual\". Use a different value only when you specifically need non-live alerts."
},
"urgency": {
"type": "array",
"items": {
"enum": [
"Immediate",
"Expected",
"Future",
"Past"
],
"type": "string"
},
"description": "Filter by urgency level."
},
"severity": {
"type": "array",
"items": {
"enum": [
"Extreme",
"Severe",
"Moderate",
"Minor",
"Unknown"
],
"type": "string"
},
"description": "Filter by severity level."
},
"certainty": {
"type": "array",
"items": {
"enum": [
"Observed",
"Likely",
"Possible",
"Unlikely",
"Unknown"
],
"type": "string"
},
"description": "Filter by certainty level."
},
"region_type": {
"enum": [
"Land",
"Marine"
],
"type": "string",
"description": "Restrict to land-based or marine alerts. Mutually exclusive with area, point, zone, and region."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"alerts",
"totalCount",
"shown",
"appliedFilters"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"mutually_exclusive_filters",
"invalid_area_code",
"invalid_point",
"invalid_zone"
],
"description": "Machine-readable failure mode. Declared by this tool: `mutually_exclusive_filters`: More than one of area, point, zone, region_type, or region provided. `invalid_area_code`: Area code is not a recognized US state, territory, or marine area. `invalid_point`: Point coordinates are malformed, outside valid bounds, or outside NWS coverage (US states, territories, and adjacent marine areas). `invalid_zone`: Zone code does not match the NWS zone-code shape. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"shown": {
"type": "number",
"description": "Number of alerts included in this response"
},
"alerts": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"event",
"headline",
"description",
"instruction",
"severity",
"urgency",
"certainty",
"areaDesc",
"sent",
"effective",
"onset",
"ends",
"expires",
"status",
"messageType",
"references",
"senderName",
"office",
"vtec",
"nwsHeadline",
"hazard",
"affectedZones"
],
"properties": {
"id": {
"type": "string",
"description": "Alert message ID. Pass it unchanged as alert_id to nws_get_alert to fetch this message again."
},
"ends": {
"type": [
"string",
"null"
],
"description": "Hazard end (ISO 8601) — when the hazard is expected to end; null when open-ended (\"until further notice\"). Distinct from expires, which is the message-refresh time."
},
"sent": {
"type": "string",
"description": "Message issuance time (ISO 8601) — when the office transmitted this CAP message. Describes the message, not the hazard: use it to judge how stale the report is."
},
"vtec": {
"type": "array",
"items": {
"type": "string",
"description": "One P-VTEC string, verbatim"
},
"description": "Raw P-VTEC strings NWS attaches (e.g., \"/O.CON.KRIW.FW.W.0031.261023T1800Z-261024T0200Z/\"), the key that tracks one event across its updates; empty when NWS sends none (e.g., Special Weather Statements)."
},
"event": {
"type": "string",
"description": "Event type (e.g., \"Tornado Warning\")"
},
"onset": {
"type": [
"string",
"null"
],
"description": "Expected hazard onset (ISO 8601). When the hazard is expected to begin."
},
"hazard": {
"anyOf": [
{
"type": "object",
"properties": {
"hailThreat": {
"type": "string",
"description": "How the hail is known (e.g., \"RADAR INDICATED\", \"OBSERVED\")"
},
"windThreat": {
"type": "string",
"description": "How the wind is known (e.g., \"RADAR INDICATED\", \"OBSERVED\")"
},
"maxHailSize": {
"type": "string",
"description": "Maximum hail size in inches, as NWS states it (e.g., \"1.00\", \"Up to .75\")"
},
"maxWindGust": {
"type": "string",
"description": "Maximum wind gust, as NWS states it (e.g., \"60 MPH\", \"34 knots\")"
},
"tornadoDetection": {
"type": "string",
"description": "Tornado detection (e.g., \"RADAR INDICATED\", \"POSSIBLE\")"
},
"flashFloodDetection": {
"type": "string",
"description": "Flash flood detection (e.g., \"RADAR INDICATED\", \"OBSERVED\", \"RADAR AND GAUGE INDICATED\")"
},
"tornadoDamageThreat": {
"type": "string",
"description": "Tornado damage-threat tag"
},
"waterspoutDetection": {
"type": "string",
"description": "Waterspout detection (e.g., \"POSSIBLE\")"
},
"eventMotionDescription": {
"type": "string",
"description": "Storm time, motion, and position in NWS encoding (e.g., \"2026-10-22T17:17:00-00:00...storm...222DEG...11KT...34.0,-118.1\")"
},
"flashFloodDamageThreat": {
"type": "string",
"description": "Flash flood damage-threat tag (e.g., \"CONSIDERABLE\")"
},
"thunderstormDamageThreat": {
"type": "string",
"description": "Thunderstorm damage-threat tag (e.g., \"CONSIDERABLE\")"
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Severe-weather tags NWS attaches, under NWS key names with values verbatim (free text such as \"Up to .75\" or \"34 knots\"). Only the tags NWS sent are present; null when it sent none."
},
"office": {
"type": [
"string",
"null"
],
"description": "Issuing forecast office code (e.g., \"RIW\"), from the issuing centre in the message's WMO header; pass it as office to nws_get_office_discussion. Null for tsunami warning centres and national test messages, which have no office discussion, and when NWS sends no usable WMO header."
},
"status": {
"type": "string",
"description": "This alert's own CAP status as reported by NWS (\"Actual\", \"Exercise\", \"System\", \"Test\", \"Draft\"). Distinct from the nws_search_alerts status input filter, which selects which alerts a search covers — with that filter at its default, every alert a search returns reads \"Actual\"."
},
"expires": {
"type": [
"string",
"null"
],
"description": "Message expiration (ISO 8601) — when NWS will issue a superseding statement. NOT when the hazard ends; the hazard window is described in the headline."
},
"urgency": {
"type": "string",
"description": "Urgency level"
},
"areaDesc": {
"type": "string",
"description": "Affected area description"
},
"headline": {
"type": [
"string",
"null"
],
"description": "Alert headline"
},
"severity": {
"type": "string",
"description": "Severity level"
},
"certainty": {
"type": "string",
"description": "Certainty level"
},
"effective": {
"type": "string",
"description": "Message effective time (ISO 8601) — when this version of the CAP message takes effect. A property of the message, not of the hazard: distinct from onset (when the hazard begins) and from expires (when a superseding message is due). Usually equals sent."
},
"references": {
"type": "array",
"items": {
"type": "object",
"required": [
"identifier",
"sent"
],
"properties": {
"sent": {
"type": "string",
"description": "When the superseded message was issued (ISO 8601)"
},
"identifier": {
"type": "string",
"description": "CAP identifier of the superseded message. Pass it unchanged as alert_id to nws_get_alert to read that message, which carries its own references."
}
},
"description": "One prior message this alert supersedes",
"additionalProperties": false
},
"description": "Prior alert messages this one supersedes, newest first by sent instant; messages sent at the same instant keep the order NWS lists them in, and one whose sent time does not parse comes last. Empty for an original issuance — never inferred when NWS reports none. nws_get_alert fetches any of them by identifier. Every reference sharing the newest sent time is an immediate predecessor (an update can merge several earlier segments); the first is one of them."
},
"senderName": {
"type": "string",
"description": "Issuing office name (e.g., \"NWS Riverton WY\"); the office code nws_get_office_discussion takes is in office"
},
"description": {
"type": [
"string",
"null"
],
"description": "Full alert description; null when NWS publishes the alert without one"
},
"instruction": {
"type": [
"string",
"null"
],
"description": "Recommended actions"
},
"messageType": {
"type": "string",
"description": "CAP message type: \"Alert\" for an original issuance, \"Update\" for a revision of an earlier message, \"Cancel\" for a cancellation."
},
"nwsHeadline": {
"type": [
"string",
"null"
],
"description": "The NWS product headline (e.g., \"RED FLAG WARNING IN EFFECT FROM NOON TO 8 PM MDT FRIDAY\"), distinct from headline; null when NWS sends none."
},
"affectedZones": {
"type": "array",
"items": {
"type": "object",
"required": [
"code",
"type"
],
"properties": {
"code": {
"type": "string",
"description": "Zone code, e.g. \"WAZ558\" (forecast) or \"WAC033\" (county)"
},
"type": {
"type": "string",
"description": "NWS zone type: \"forecast\", \"county\", or \"fire\" (\"unknown\" when upstream reports a shape this server cannot type). A \"forecast\" code has a zone text forecast: pass it to nws_get_zone_forecast. A \"fire\" code has a segment in its office's Fire Weather Planning Forecast: call nws_get_office_discussion with office from this alert's office field, product_type \"FWF\", and sections [code]. All types are valid values for the nws_search_alerts zone filter."
}
},
"description": "Affected zone with its NWS zone type",
"additionalProperties": false
},
"description": "Affected zones, each with the zone type that decides where it can chain"
}
},
"description": "Single alert message with event, severity, area, and timing",
"additionalProperties": false
},
"description": "Matching alerts for this page (at most the applied limit, which never exceeds 25)"
},
"notice": {
"type": "string",
"description": "Guidance when the requested limit exceeded the page cap, when no alerts matched (echoes applied filters and suggests how to broaden), when matches remain beyond this page, or when the supplied cursor points past the end of the match set."
},
"nextCursor": {
"type": "string",
"description": "Opaque token for the next page of matches — pass it back as `cursor` on its own; it carries this query's filters and page size. Omitted when this is the last page."
},
"totalCount": {
"type": "number",
"description": "Total distinct alerts matching the filters in this fetch, before the page window is applied. NWS repeats some alerts verbatim within one response; the copies are collapsed on id, so this counts each alert once. Compare against shown to tell whether matches were withheld from this page."
},
"appliedFilters": {
"type": "string",
"description": "Summary of applied search filters"
},
"effectiveLimit": {
"type": "number",
"description": "The page size applied instead of requestedLimit; continued pages keep it. Absent when the limit was within the cap."
},
"requestedLimit": {
"type": "number",
"description": "The limit asked for, when it exceeded the 25-alert page cap; absent otherwise."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_get_alert — Nws Get Alert
Fetch one NWS alert message by ID — a current alert, or an earlier message that an update or cancellation has since superseded and that an active-alert search no longer returns. Takes an id from nws_search_alerts or a references[].identifier from any alert, and returns the same alert fields nws_search_alerts does. The message carries its own references, newest first, so a revision chain is walked one call per message. Every reference sharing the newest sent time is an immediate predecessor (an update can merge several earlier segments), so references[0] is one of them, not always the only one. NWS serves messages for about 7 days after they are sent.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"alert_id"
],
"properties": {
"alert_id": {
"type": "string",
"pattern": "^\\s*(?:urn:oid:2\\.49\\.0\\.1\\.840\\.0(?:\\.[0-9a-f]{40}\\.[0-9]{3}\\.[0-9]+|-KEEPALIVE-[0-9]+))\\s*$",
"description": "NWS alert message ID, e.g. \"urn:oid:2.49.0.1.840.0.654087301e4bfcbe71d24494c26a965e54d3a1ad.001.1\": the id of an alert from nws_search_alerts, or the identifier of one of its references. Pass it exactly as returned; IDs are case-sensitive."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"alert"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"alert": {
"type": "object",
"required": [
"id",
"event",
"headline",
"description",
"instruction",
"severity",
"urgency",
"certainty",
"areaDesc",
"sent",
"effective",
"onset",
"ends",
"expires",
"status",
"messageType",
"references",
"senderName",
"office",
"vtec",
"nwsHeadline",
"hazard",
"affectedZones"
],
"properties": {
"id": {
"type": "string",
"description": "Alert message ID. Pass it unchanged as alert_id to nws_get_alert to fetch this message again."
},
"ends": {
"type": [
"string",
"null"
],
"description": "Hazard end (ISO 8601) — when the hazard is expected to end; null when open-ended (\"until further notice\"). Distinct from expires, which is the message-refresh time."
},
"sent": {
"type": "string",
"description": "Message issuance time (ISO 8601) — when the office transmitted this CAP message. Describes the message, not the hazard: use it to judge how stale the report is."
},
"vtec": {
"type": "array",
"items": {
"type": "string",
"description": "One P-VTEC string, verbatim"
},
"description": "Raw P-VTEC strings NWS attaches (e.g., \"/O.CON.KRIW.FW.W.0031.261023T1800Z-261024T0200Z/\"), the key that tracks one event across its updates; empty when NWS sends none (e.g., Special Weather Statements)."
},
"event": {
"type": "string",
"description": "Event type (e.g., \"Tornado Warning\")"
},
"onset": {
"type": [
"string",
"null"
],
"description": "Expected hazard onset (ISO 8601). When the hazard is expected to begin."
},
"hazard": {
"anyOf": [
{
"type": "object",
"properties": {
"hailThreat": {
"type": "string",
"description": "How the hail is known (e.g., \"RADAR INDICATED\", \"OBSERVED\")"
},
"windThreat": {
"type": "string",
"description": "How the wind is known (e.g., \"RADAR INDICATED\", \"OBSERVED\")"
},
"maxHailSize": {
"type": "string",
"description": "Maximum hail size in inches, as NWS states it (e.g., \"1.00\", \"Up to .75\")"
},
"maxWindGust": {
"type": "string",
"description": "Maximum wind gust, as NWS states it (e.g., \"60 MPH\", \"34 knots\")"
},
"tornadoDetection": {
"type": "string",
"description": "Tornado detection (e.g., \"RADAR INDICATED\", \"POSSIBLE\")"
},
"flashFloodDetection": {
"type": "string",
"description": "Flash flood detection (e.g., \"RADAR INDICATED\", \"OBSERVED\", \"RADAR AND GAUGE INDICATED\")"
},
"tornadoDamageThreat": {
"type": "string",
"description": "Tornado damage-threat tag"
},
"waterspoutDetection": {
"type": "string",
"description": "Waterspout detection (e.g., \"POSSIBLE\")"
},
"eventMotionDescription": {
"type": "string",
"description": "Storm time, motion, and position in NWS encoding (e.g., \"2026-10-22T17:17:00-00:00...storm...222DEG...11KT...34.0,-118.1\")"
},
"flashFloodDamageThreat": {
"type": "string",
"description": "Flash flood damage-threat tag (e.g., \"CONSIDERABLE\")"
},
"thunderstormDamageThreat": {
"type": "string",
"description": "Thunderstorm damage-threat tag (e.g., \"CONSIDERABLE\")"
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Severe-weather tags NWS attaches, under NWS key names with values verbatim (free text such as \"Up to .75\" or \"34 knots\"). Only the tags NWS sent are present; null when it sent none."
},
"office": {
"type": [
"string",
"null"
],
"description": "Issuing forecast office code (e.g., \"RIW\"), from the issuing centre in the message's WMO header; pass it as office to nws_get_office_discussion. Null for tsunami warning centres and national test messages, which have no office discussion, and when NWS sends no usable WMO header."
},
"status": {
"type": "string",
"description": "This alert's own CAP status as reported by NWS (\"Actual\", \"Exercise\", \"System\", \"Test\", \"Draft\"). Distinct from the nws_search_alerts status input filter, which selects which alerts a search covers — with that filter at its default, every alert a search returns reads \"Actual\"."
},
"expires": {
"type": [
"string",
"null"
],
"description": "Message expiration (ISO 8601) — when NWS will issue a superseding statement. NOT when the hazard ends; the hazard window is described in the headline."
},
"urgency": {
"type": "string",
"description": "Urgency level"
},
"areaDesc": {
"type": "string",
"description": "Affected area description"
},
"headline": {
"type": [
"string",
"null"
],
"description": "Alert headline"
},
"severity": {
"type": "string",
"description": "Severity level"
},
"certainty": {
"type": "string",
"description": "Certainty level"
},
"effective": {
"type": "string",
"description": "Message effective time (ISO 8601) — when this version of the CAP message takes effect. A property of the message, not of the hazard: distinct from onset (when the hazard begins) and from expires (when a superseding message is due). Usually equals sent."
},
"references": {
"type": "array",
"items": {
"type": "object",
"required": [
"identifier",
"sent"
],
"properties": {
"sent": {
"type": "string",
"description": "When the superseded message was issued (ISO 8601)"
},
"identifier": {
"type": "string",
"description": "CAP identifier of the superseded message. Pass it unchanged as alert_id to nws_get_alert to read that message, which carries its own references."
}
},
"description": "One prior message this alert supersedes",
"additionalProperties": false
},
"description": "Prior alert messages this one supersedes, newest first by sent instant; messages sent at the same instant keep the order NWS lists them in, and one whose sent time does not parse comes last. Empty for an original issuance — never inferred when NWS reports none. nws_get_alert fetches any of them by identifier. Every reference sharing the newest sent time is an immediate predecessor (an update can merge several earlier segments); the first is one of them."
},
"senderName": {
"type": "string",
"description": "Issuing office name (e.g., \"NWS Riverton WY\"); the office code nws_get_office_discussion takes is in office"
},
"description": {
"type": [
"string",
"null"
],
"description": "Full alert description; null when NWS publishes the alert without one"
},
"instruction": {
"type": [
"string",
"null"
],
"description": "Recommended actions"
},
"messageType": {
"type": "string",
"description": "CAP message type: \"Alert\" for an original issuance, \"Update\" for a revision of an earlier message, \"Cancel\" for a cancellation."
},
"nwsHeadline": {
"type": [
"string",
"null"
],
"description": "The NWS product headline (e.g., \"RED FLAG WARNING IN EFFECT FROM NOON TO 8 PM MDT FRIDAY\"), distinct from headline; null when NWS sends none."
},
"affectedZones": {
"type": "array",
"items": {
"type": "object",
"required": [
"code",
"type"
],
"properties": {
"code": {
"type": "string",
"description": "Zone code, e.g. \"WAZ558\" (forecast) or \"WAC033\" (county)"
},
"type": {
"type": "string",
"description": "NWS zone type: \"forecast\", \"county\", or \"fire\" (\"unknown\" when upstream reports a shape this server cannot type). A \"forecast\" code has a zone text forecast: pass it to nws_get_zone_forecast. A \"fire\" code has a segment in its office's Fire Weather Planning Forecast: call nws_get_office_discussion with office from this alert's office field, product_type \"FWF\", and sections [code]. All types are valid values for the nws_search_alerts zone filter."
}
},
"description": "Affected zone with its NWS zone type",
"additionalProperties": false
},
"description": "Affected zones, each with the zone type that decides where it can chain"
}
},
"description": "Single alert message with event, severity, area, and timing",
"additionalProperties": false
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"alert_not_found"
],
"description": "Machine-readable failure mode. Declared by this tool: `alert_not_found`: alert_id is not an NWS alert ID, or NWS has no message with that ID. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_get_alert_counts — Nws Get Alert Counts
Count active weather alerts nationwide, per state/territory or marine area, and per marine region, in one small response — the answer to "how many alerts are active, and where" without fetching the alerts themselves. Counts cover every message status, Test and Exercise included, so totalAlerts can run above the totalCount a national nws_search_alerts search reports under its default status of Actual. An alert counts once in each area its zones fall in, so the area counts can sum past totalAlerts; landAlerts plus marineAlerts equals totalAlerts. Takes no filters. For counts per zone or under a filter, call nws_search_alerts with that zone or filter and read its totalCount.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"totalAlerts",
"landAlerts",
"marineAlerts",
"areas",
"regions"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"areas": {
"type": "object",
"description": "Active alert counts keyed by state/territory code (e.g., \"WA\", \"PR\") or marine area code (e.g., \"PZ\", \"GM\"). Only areas with an active alert appear. An alert counts once in each area its zones fall in, so these can sum past totalAlerts. Area \"AL\" is Alabama; Alaska waters are region \"AL\" in regions.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "number"
}
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Machine-readable failure mode."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"regions": {
"type": "object",
"description": "Active marine alert counts keyed by marine region: \"AL\" (Alaska waters), \"AT\" (Atlantic Ocean), \"GL\" (Great Lakes), \"GM\" (Gulf of Mexico), \"PA\" (Eastern Pacific and US West Coast), \"PI\" (Central and Western Pacific). Only regions with an active alert appear, so the map is empty when no marine alert is active.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "number"
}
},
"landAlerts": {
"type": "number",
"description": "Active alerts affecting land zones."
},
"totalAlerts": {
"type": "number",
"description": "Active alerts nationwide across every message status (Actual, Exercise, System, Test, Draft). Can exceed the totalCount of a national nws_search_alerts search, which counts status Actual by default."
},
"marineAlerts": {
"type": "number",
"description": "Active alerts affecting marine zones. landAlerts + marineAlerts = totalAlerts."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_get_observations — Nws Get Observations
Get current weather observations (actual measured conditions). Accepts coordinates (resolves nearest station automatically) or a station ID directly (e.g., "KSEA").
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"latitude": {
"type": "number",
"maximum": 90,
"minimum": -90,
"description": "Latitude for automatic station resolution. Use with longitude. Ignored if station_id is provided."
},
"longitude": {
"type": "number",
"maximum": 180,
"minimum": -180,
"description": "Longitude for automatic station resolution. Use with latitude. Ignored if station_id is provided."
},
"station_id": {
"type": "string",
"pattern": "^\\s*(?:[A-Za-z0-9]+\\s*)?$",
"description": "Station identifier directly (e.g., \"KSEA\", \"KORD\"). Use nws_find_stations to discover station IDs."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"stationId",
"stationName",
"timestamp",
"timeZone",
"textDescription",
"temperatureC",
"dewpointC",
"windSpeedKmh",
"windDirectionDeg",
"windGustKmh",
"barometricPressurePa",
"visibilityM",
"relativeHumidityPct",
"heatIndexC",
"windChillC",
"precipitationLastHourMm",
"precipitationLast3HoursMm",
"precipitationLast6HoursMm",
"cloudLayers",
"station",
"observedAt"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"missing_input",
"station_not_found",
"no_observations",
"no_stations_nearby",
"out_of_scope"
],
"description": "Machine-readable failure mode. Declared by this tool: `missing_input`: Neither station_id nor a (latitude, longitude) pair was provided. `station_not_found`: Station ID does not exist in the NWS network. `no_observations`: Station has no recent observations available. `no_stations_nearby`: No observation stations exist near the requested coordinates. `out_of_scope`: Coordinates fall outside US National Weather Service coverage. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"notice": {
"type": "string",
"description": "Guidance when the latest observation is more than 2 hours old or most measurements are unavailable from this station."
},
"station": {
"type": "string",
"description": "Station ID that served the observation (e.g., \"KSEA\")"
},
"timeZone": {
"type": [
"string",
"null"
],
"description": "Station time zone when known"
},
"dewpointC": {
"type": [
"number",
"null"
],
"description": "Dewpoint in Celsius, to one decimal"
},
"stationId": {
"type": "string",
"description": "Observation station ID"
},
"timestamp": {
"type": "string",
"description": "Observation time (ISO 8601)"
},
"heatIndexC": {
"type": [
"number",
"null"
],
"description": "Heat index in Celsius, to one decimal"
},
"observedAt": {
"type": "string",
"description": "Observation timestamp (ISO 8601)"
},
"windChillC": {
"type": [
"number",
"null"
],
"description": "Wind chill in Celsius, to one decimal"
},
"cloudLayers": {
"type": "array",
"items": {
"type": "object",
"required": [
"amount",
"baseM"
],
"properties": {
"baseM": {
"type": [
"number",
"null"
],
"description": "Cloud base height in meters"
},
"amount": {
"type": "string",
"description": "Cloud cover (e.g., \"FEW\", \"SCT\", \"BKN\", \"OVC\")"
}
},
"description": "Single cloud layer with cover amount and base height",
"additionalProperties": false
},
"description": "Cloud layer information"
},
"stationName": {
"type": "string",
"description": "Station name"
},
"visibilityM": {
"type": [
"number",
"null"
],
"description": "Visibility in meters"
},
"windGustKmh": {
"type": [
"number",
"null"
],
"description": "Wind gust in km/h"
},
"temperatureC": {
"type": [
"number",
"null"
],
"description": "Temperature in Celsius, to one decimal (e.g., 8.3)"
},
"windSpeedKmh": {
"type": [
"number",
"null"
],
"description": "Wind speed in km/h"
},
"textDescription": {
"type": "string",
"description": "Conditions summary (e.g., \"Mostly Cloudy\")"
},
"windDirectionDeg": {
"type": [
"number",
"null"
],
"description": "Wind direction in degrees (0-360)"
},
"relativeHumidityPct": {
"type": [
"number",
"null"
],
"description": "Relative humidity in percent (0-100)"
},
"barometricPressurePa": {
"type": [
"number",
"null"
],
"description": "Barometric pressure in Pascals"
},
"precipitationLastHourMm": {
"type": [
"number",
"null"
],
"description": "Precipitation in the past hour in mm, to 0.1 mm. 0 is a trace (under 0.01 in), not a dry hour; null means no amount was reported, the usual value for a dry hour and on 5-minute reports."
},
"precipitationLast3HoursMm": {
"type": [
"number",
"null"
],
"description": "Precipitation in the past 3 hours in mm, to 0.1 mm, carried by the hourly reports nearest 03, 09, 15, and 21 UTC. 0 is a trace (under 0.01 in); null means no amount was reported."
},
"precipitationLast6HoursMm": {
"type": [
"number",
"null"
],
"description": "Precipitation in the past 6 hours in mm, to 0.1 mm, carried by the hourly reports nearest 00, 06, 12, and 18 UTC. 0 is a trace (under 0.01 in); null means no amount was reported."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_get_observation_history — Nws Get Observation History
Get a station's recent observation history, newest first — the trend behind the single latest reading nws_get_observations returns (is pressure falling, is the wind picking up). NWS keeps about the last 7 days per station, and a busy airport station reports as often as every 5 minutes, so a day can run past 100 observations: narrow with start (inclusive) and end (exclusive), and page back to older observations with nextCursor. Takes a station ID; use nws_find_stations to find one near a coordinate.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"station_id"
],
"properties": {
"end": {
"type": "string",
"pattern": "^\\s*(?:\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,6})?(?:Z|[+-]\\d{2}:\\d{2})\\s*)?$",
"description": "Time to stop before (exclusive), in the same format as start. Omit to start from the most recent observation."
},
"limit": {
"type": "integer",
"default": 24,
"maximum": 10000,
"minimum": 1,
"description": "Observations per page, newest first. A page holds at most 100; a larger limit (up to 10000) is served as 100 and reported through requestedLimit and effectiveLimit. When older observations remain in the window, the response carries nextCursor; pass it back as cursor for them."
},
"start": {
"type": "string",
"pattern": "^\\s*(?:\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,6})?(?:Z|[+-]\\d{2}:\\d{2})\\s*)?$",
"description": "Earliest observation time to include (inclusive), as an ISO 8601 date-time with seconds and an offset (e.g., \"2026-09-30T00:00:00Z\" or \"2026-09-29T17:00:00-07:00\"). Omit to reach back as far as NWS keeps, about 7 days."
},
"cursor": {
"type": "string",
"description": "Opaque continuation token from a previous response's nextCursor. Omit for the first page. It carries that query's start, end, and applied limit, so those inputs apply to the first page only. Each page continues from just before the oldest observation of the one before it, so pages neither repeat nor skip an observation."
},
"station_id": {
"type": "string",
"pattern": "^\\s*[A-Za-z0-9]+\\s*$",
"minLength": 1,
"description": "Observation station ID (e.g., \"KSEA\"), case-insensitive. Use nws_find_stations to discover station IDs near a coordinate."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"stationId",
"stationName",
"timeZone",
"observations",
"shown"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cap": {
"type": "number",
"description": "The page limit this page holds, when truncated is true"
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"station_not_found",
"invalid_time_window"
],
"description": "Machine-readable failure mode. Declared by this tool: `station_not_found`: Station ID is malformed or does not exist in the NWS network. `invalid_time_window`: start or end is not a valid ISO 8601 date-time with seconds and an offset, or start is not before end. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"shown": {
"type": "number",
"description": "Number of observations returned in this page"
},
"notice": {
"type": "string",
"description": "Guidance when the requested limit exceeded the page cap, when the window held no observations (NWS keeps about the last 7 days), or when older observations remain beyond this page."
},
"timeZone": {
"type": [
"string",
"null"
],
"description": "Station time zone when known"
},
"stationId": {
"type": "string",
"description": "Observation station ID, uppercased"
},
"truncated": {
"type": "boolean",
"description": "True when older observations remain in the window past this page; continue with nextCursor."
},
"nextCursor": {
"type": "string",
"description": "Opaque token for the next, older page — pass it back as cursor. Present only when older observations remain in the window; omitted on the last page."
},
"stationName": {
"type": "string",
"description": "Station name"
},
"observations": {
"type": "array",
"items": {
"type": "object",
"required": [
"timestamp",
"textDescription",
"temperatureC",
"dewpointC",
"windSpeedKmh",
"windDirectionDeg",
"windGustKmh",
"barometricPressurePa",
"visibilityM",
"relativeHumidityPct",
"heatIndexC",
"windChillC",
"precipitationLastHourMm",
"precipitationLast3HoursMm",
"precipitationLast6HoursMm",
"cloudLayers"
],
"properties": {
"dewpointC": {
"type": [
"number",
"null"
],
"description": "Dewpoint in Celsius, to one decimal"
},
"timestamp": {
"type": "string",
"description": "Observation time (ISO 8601)"
},
"heatIndexC": {
"type": [
"number",
"null"
],
"description": "Heat index in Celsius, to one decimal"
},
"windChillC": {
"type": [
"number",
"null"
],
"description": "Wind chill in Celsius, to one decimal"
},
"cloudLayers": {
"type": "array",
"items": {
"type": "object",
"required": [
"amount",
"baseM"
],
"properties": {
"baseM": {
"type": [
"number",
"null"
],
"description": "Cloud base height in meters"
},
"amount": {
"type": "string",
"description": "Cloud cover (e.g., \"FEW\", \"SCT\", \"BKN\", \"OVC\")"
}
},
"description": "Single cloud layer with cover amount and base height",
"additionalProperties": false
},
"description": "Cloud layer information"
},
"visibilityM": {
"type": [
"number",
"null"
],
"description": "Visibility in meters"
},
"windGustKmh": {
"type": [
"number",
"null"
],
"description": "Wind gust in km/h"
},
"temperatureC": {
"type": [
"number",
"null"
],
"description": "Temperature in Celsius, to one decimal (e.g., 8.3)"
},
"windSpeedKmh": {
"type": [
"number",
"null"
],
"description": "Wind speed in km/h"
},
"textDescription": {
"type": "string",
"description": "Conditions summary (e.g., \"Mostly Cloudy\"); empty when not reported"
},
"windDirectionDeg": {
"type": [
"number",
"null"
],
"description": "Wind direction in degrees (0-360)"
},
"relativeHumidityPct": {
"type": [
"number",
"null"
],
"description": "Relative humidity in percent (0-100)"
},
"barometricPressurePa": {
"type": [
"number",
"null"
],
"description": "Barometric pressure in Pascals"
},
"precipitationLastHourMm": {
"type": [
"number",
"null"
],
"description": "Precipitation in the past hour in mm, to 0.1 mm. 0 is a trace (under 0.01 in), not a dry hour; null means no amount was reported, the usual value for a dry hour and on 5-minute reports."
},
"precipitationLast3HoursMm": {
"type": [
"number",
"null"
],
"description": "Precipitation in the past 3 hours in mm, to 0.1 mm, carried by the hourly reports nearest 03, 09, 15, and 21 UTC. 0 is a trace (under 0.01 in); null means no amount was reported."
},
"precipitationLast6HoursMm": {
"type": [
"number",
"null"
],
"description": "Precipitation in the past 6 hours in mm, to 0.1 mm, carried by the hourly reports nearest 00, 06, 12, and 18 UTC. 0 is a trace (under 0.01 in); null means no amount was reported."
}
},
"description": "One observation; a measurement the station did not report is null, never 0",
"additionalProperties": false
},
"description": "Observations in the window, newest first"
},
"effectiveLimit": {
"type": "number",
"description": "The page size applied instead of requestedLimit; continued pages keep it. Absent when the limit was within the cap."
},
"requestedLimit": {
"type": "number",
"description": "The limit asked for, when it exceeded the 100-observation page cap; absent otherwise."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_find_stations — Nws Find Stations
Find weather observation stations near a location. Returns stations sorted by proximity with distance and bearing. Use to discover station IDs for nws_get_observations.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"latitude",
"longitude"
],
"properties": {
"limit": {
"type": "integer",
"default": 10,
"maximum": 10000,
"minimum": 1,
"description": "Max stations per page. A page holds at most 50; a larger limit (up to 10000) is served as 50 and reported through requestedLimit and effectiveLimit. totalCount still reports every station near the point, so pass the returned nextCursor as cursor to reach the rest."
},
"cursor": {
"type": "string",
"description": "Opaque continuation token from a previous response's nextCursor. Omit for the first page. The token carries its own page size, so limit applies to the first page only. Every call re-fetches the station list, so pages are contiguous within one response; the registry changes rarely, but a later call can window an updated list."
},
"latitude": {
"type": "number",
"maximum": 90,
"minimum": -90,
"description": "Center latitude for proximity search."
},
"longitude": {
"type": "number",
"maximum": 180,
"minimum": -180,
"description": "Center longitude for proximity search."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"stations",
"totalCount",
"shown"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"out_of_scope"
],
"description": "Machine-readable failure mode. Declared by this tool: `out_of_scope`: Coordinates fall outside US National Weather Service coverage. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"shown": {
"type": "number",
"description": "Number of stations returned in this page"
},
"notice": {
"type": "string",
"description": "Guidance when the requested limit exceeded the page cap, when no stations were found near the requested coordinates, when stations remain beyond this page, or when the supplied cursor points past the end of the list."
},
"stations": {
"type": "array",
"items": {
"type": "object",
"required": [
"stationId",
"name",
"distanceKm",
"bearing",
"elevationM",
"timeZone",
"county",
"forecastZone"
],
"properties": {
"name": {
"type": "string",
"description": "Station name"
},
"county": {
"type": "string",
"description": "County zone code (e.g., \"WAC033\")"
},
"bearing": {
"type": "string",
"description": "Compass bearing from query point (e.g., \"NW\")"
},
"timeZone": {
"type": "string",
"description": "IANA time zone"
},
"stationId": {
"type": "string",
"description": "Station identifier (e.g., \"KSEA\")"
},
"distanceKm": {
"type": "number",
"description": "Distance from query point in kilometers"
},
"elevationM": {
"type": [
"number",
"null"
],
"description": "Elevation in meters"
},
"forecastZone": {
"type": "string",
"description": "Forecast zone code (e.g., \"WAZ315\")"
}
},
"description": "Observation station record with identity, location, and zone codes",
"additionalProperties": false
},
"description": "Nearby stations sorted by distance"
},
"nextCursor": {
"type": "string",
"description": "Opaque token for the next page of stations — pass it back as `cursor`. Omitted when this is the last page."
},
"totalCount": {
"type": "number",
"description": "Total observation stations available near this location before the page limit was applied — NOT the number returned in this page, which is shown. Same value on every page of one query; compare it against shown to tell whether stations were withheld."
},
"effectiveLimit": {
"type": "number",
"description": "The page size applied instead of requestedLimit; continued pages keep it. Absent when the limit was within the cap."
},
"requestedLimit": {
"type": "number",
"description": "The limit asked for, when it exceeded the 50-station page cap; absent otherwise."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_list_alert_types — Nws List Alert Types
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.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"count",
"eventTypes"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"count": {
"type": "number",
"description": "Number of event types"
},
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Machine-readable failure mode."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"eventTypes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Alert event type names sorted alphabetically"
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_get_office_discussion — Nws Get Office Discussion
Get the latest narrative forecast product from a Weather Forecast Office (WFO). The default product is AFD (Area Forecast Discussion), which explains the meteorological reasoning behind the forecast — synoptic setup, model guidance, and forecaster confidence. Other types: HWO (Hazardous Weather Outlook, 1-7 day severe/flood/winter outlook), ZFP (Zone Forecast Product, zone-by-zone text), SPS (Special Weather Statement, short-fuse advisory), FWF (Fire Weather Planning Forecast, one segment per fire weather zone). The office code is the 3-letter WFO identifier returned as the "office" field by nws_get_forecast. A product over 24,000 bytes (most ZFPs and FWFs) comes back as an outline of its sections — AFD section names, or ZFP/HWO/SPS/FWF zone segments with their area names — with each section's size, instead of the text; re-call with sections to get the ones you need. sections also works on a product of any size, to read one AFD section or one zone's forecast. For an alert zone typed "fire" (Red Flag Warning, Fire Weather Watch), pass the alert's "office" field as office, product_type "FWF", and the zone code in sections.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"office"
],
"properties": {
"office": {
"type": "string",
"pattern": "^\\s*[A-Za-z0-9]{2,3}\\s*$",
"minLength": 1,
"description": "Product location code of 2–3 letters or digits, case-insensitive — usually the 3-letter Weather Forecast Office (WFO) code (e.g., \"SEW\" for Seattle, \"LOX\" for Los Angeles), returned as the \"office\" field in nws_get_forecast output. Some offices file a product under other codes: Anchorage files its ZFP under \"AER\" (Anchorage East) and \"ALU\" (Anchorage West), not \"AFC\"; San Juan files its ZFP under \"PR\", and Guam its SPS under \"PQ1\"."
},
"sections": {
"type": "array",
"items": {
"type": "string",
"maxLength": 200
},
"maxItems": 100,
"description": "Sections to return instead of the whole product: AFD section names, case-insensitive (e.g., \"DISCUSSION\", \"AVIATION\"), or zone codes for ZFP/HWO/SPS/FWF (e.g., \"WAZ315\"; a code inside a listed range such as FLZ076>078 selects that segment). Take names from the outline. Returns the product header plus every matching section verbatim, in product order, followed by the product's closing lines (forecaster credits, links). Omit for the whole product, or its outline when it is too large."
},
"product_type": {
"enum": [
"AFD",
"HWO",
"ZFP",
"SPS",
"FWF"
],
"type": "string",
"default": "AFD",
"description": "Product type code. AFD (Area Forecast Discussion) — meteorological reasoning, model analysis, forecaster confidence. HWO (Hazardous Weather Outlook) — 1-7 day outlook for severe weather, flooding, winter weather. ZFP (Zone Forecast Product) — detailed zone-by-zone text forecast. SPS (Special Weather Statement) — short-fuse advisory for notable non-warning weather. FWF (Fire Weather Planning Forecast) — fire weather discussion plus a forecast segment per fire weather zone (e.g., humidity and wind); select a zone with sections."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"issuanceTime",
"issuingOffice",
"productCode",
"productName",
"wmoCollectiveId"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"no_products",
"unknown_section"
],
"description": "Machine-readable failure mode. Declared by this tool: `no_products`: Office code is unknown, or no product of the requested type is filed under it: episodic types (SPS, HWO) are commonly empty, some offices file AFD or ZFP under other location codes, and some offices issue no FWF. `unknown_section`: A sections entry matches no section of the latest product. Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"notice": {
"type": "string",
"description": "Set when the product is outlined (with a worked sections re-call) or when sections selected part of it (how many of how many sections came back)."
},
"outline": {
"type": "array",
"items": {
"type": "object",
"required": [
"name",
"bytes"
],
"properties": {
"name": {
"type": "string",
"description": "AFD section name (e.g., \"AVIATION\"), or a zone segment's zone codes as issued, ranges written NNN>MMM (e.g., \"FLZ076>078, IDZ001\"). Pass it, or any one zone code it covers, in sections."
},
"bytes": {
"type": "number",
"description": "Size of the section text in bytes."
},
"label": {
"type": "string",
"description": "Area name line of a zone segment (e.g., \"City of Seattle\")."
}
},
"description": "One section of the product",
"additionalProperties": false
},
"description": "Sections of a product too large to inline, largest first. Present only in place of productText."
},
"productCode": {
"type": "string",
"description": "Product type code (e.g., \"AFD\")."
},
"productName": {
"type": "string",
"description": "Full product name (e.g., \"Area Forecast Discussion\")."
},
"productText": {
"type": "string",
"description": "Narrative product text as issued by the forecaster: the whole product, or the product header followed by each selected section when sections was given. Absent when outline is returned."
},
"issuanceTime": {
"type": "string",
"description": "When the product was issued (ISO 8601), e.g., \"2026-05-30T10:33:00+00:00\"."
},
"issuingOffice": {
"type": "string",
"description": "Issuing office call sign (e.g., \"KSEW\"). Includes the K/P prefix, unlike the input office code."
},
"wmoCollectiveId": {
"type": "string",
"description": "WMO collective identifier (e.g., \"FXUS66\"). Identifies the product family in international message routing."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}nws_get_zone_forecast — Nws Get Zone Forecast
Get the text forecast for an NWS forecast zone. Returns named forecast periods (e.g., "Today", "Tonight", "Monday") with detailed narrative text — the human-readable, zone-level forecast written by local forecasters. Completes the alert-to-forecast chain: nws_search_alerts returns each affected zone in "affectedZones" as a code plus a type, and nws_find_stations returns codes in the "forecastZone" column. Only affectedZones entries with type "forecast" work here; entries typed "county" have no text forecast upstream and will not resolve. An entry typed "fire" has its forecast in a segment of the office's Fire Weather Planning Forecast: call nws_get_office_discussion with office set to the alert's "office" field, product_type "FWF", and sections set to the zone code; a fire zone code that is also a public zone code (e.g., "NDZ040") returns that public zone's forecast here, not the fire weather forecast. Marine forecast zones vary: many coastal zones serve a text forecast of wind and seas (e.g., "PZZ251"), while offshore zones (e.g., "GMZ056") and some coastal ones have none. Zone codes follow the pattern XXZ### (e.g., "WAZ315" for the City of Seattle).
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"zone_id"
],
"properties": {
"zone_id": {
"type": "string",
"pattern": "^\\s*[A-Za-z]{2}[Zz]\\d{3}\\s*$",
"minLength": 1,
"description": "NWS forecast zone code (e.g., \"WAZ315\" for the City of Seattle, or a marine zone such as \"PZZ251\"). Returned as \"forecastZone\" by nws_get_forecast and nws_find_stations, or as the \"code\" of an \"affectedZones\" entry with type \"forecast\" in nws_search_alerts. Format: two-letter state or marine area code + \"Z\" + three-digit number."
}
},
"additionalProperties": false
}{
"type": "object",
"anyOf": [
{
"not": {
"required": [
"error"
]
},
"required": [
"zoneId",
"updated",
"periods",
"periodCount"
]
},
{
"required": [
"error"
]
}
],
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": -9007199254740991,
"description": "JSON-RPC error code for this failure."
},
"data": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"examples": [
"zone_not_found",
"zone_forecast_unavailable",
"marine_forecast_unsupported"
],
"description": "Machine-readable failure mode. Declared by this tool: `zone_not_found`: Zone code is not a valid NWS forecast zone. `zone_forecast_unavailable`: Zone is a valid land forecast zone, but NWS has no text forecast for it. `marine_forecast_unsupported`: Zone is a marine forecast zone NWS publishes no text forecast for (availability varies by zone). Other values are possible when a failure originates below the handler."
},
"recovery": {
"type": "object",
"required": [
"hint"
],
"properties": {
"hint": {
"type": "string"
}
},
"description": "Actionable next step for the caller.",
"additionalProperties": {}
},
"retryable": {
"type": "boolean",
"description": "Whether retrying may succeed."
}
},
"additionalProperties": {}
},
"message": {
"type": "string",
"description": "Human-readable description of what went wrong."
}
},
"description": "Present when the call failed. Absent on success.",
"additionalProperties": {}
},
"zoneId": {
"type": "string",
"description": "Zone ID, uppercased (e.g., \"WAZ315\" for input \"waz315\")."
},
"periods": {
"type": "array",
"items": {
"type": "object",
"required": [
"number",
"name",
"detailedForecast"
],
"properties": {
"name": {
"type": "string",
"description": "Period name (e.g., \"Today\", \"Tonight\", \"Monday\")."
},
"number": {
"type": "number",
"description": "Period sequence number, starting at 1."
},
"detailedForecast": {
"type": "string",
"description": "Full narrative forecast for this period, written by local forecasters (e.g., \"Partly cloudy. Highs in the upper 60s. Southwest winds 10 to 15 mph.\")."
}
},
"description": "Single forecast period with name and narrative",
"additionalProperties": false
},
"description": "Forecast periods in chronological order, typically covering 7 days."
},
"updated": {
"type": "string",
"description": "When the zone forecast was last updated (ISO 8601 with timezone offset)."
},
"periodCount": {
"type": "number",
"description": "Number of forecast periods returned."
}
},
"additionalProperties": false
}{
"readOnlyHint": true
}Prompts
0 advertised
Resources
2 advertised
NWS Alert Event Types — NWS Alert Event Types
Static list of all valid NWS alert event type names. Useful reference when constructing event filters for nws_search_alerts.
nws://alert-typesnws-weather-guide
Reconcile nws_* forecasts, active alerts, station trends, and forecaster discussions for a time-and-location weather decision. Use when planning outdoor activity, checking a claimed all-clear, comparing an alert update, or explaining changing conditions across these sources.
skill://nws-weather-guide/SKILL.mdio.modelcontextprotocol/skills
skill://{+path}30-day availability
Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.
- Successful checks
- 1 of 1 (100%)
- Average latency
- 653 ms
- 95th percentile latency
- 653 ms
Maintenance history
Public check and source-refresh events. Editorial and ownership records remain private.
- · probe · passed · 653 ms · metadata changed · 10 tool(s), 2 resource(s), 1 resource template(s), 0 prompt(s)
Connect from your client
Each snippet registers the same endpoint; pick the client you use.
Claude Code
claude mcp add --transport http nws-weather-mcp-server-caseyjhand https://nws.caseyjhand.com/mcpCodex
codex mcp add nws-weather-mcp-server-caseyjhand --url https://nws.caseyjhand.com/mcpCursor
{
"mcpServers": {
"nws-weather-mcp-server-caseyjhand": {
"url": "https://nws.caseyjhand.com/mcp"
}
}
}Cline
{
"mcpServers": {
"nws-weather-mcp-server-caseyjhand": {
"type": "streamableHttp",
"url": "https://nws.caseyjhand.com/mcp",
"disabled": false
}
}
}VS Code
{
"servers": {
"nws-weather-mcp-server-caseyjhand": {
"type": "http",
"url": "https://nws.caseyjhand.com/mcp"
}
}
}Gemini CLI
gemini mcp add --transport http nws-weather-mcp-server-caseyjhand https://nws.caseyjhand.com/mcpClaude Desktop
https://nws.caseyjhand.com/mcpWindsurf
{
"mcpServers": {
"nws-weather-mcp-server-caseyjhand": {
"serverUrl": "https://nws.caseyjhand.com/mcp"
}
}
}Let your agent find its tools
Find servers like nws-weather-mcp-server from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.