@dangahagan/weather-mcp 1.31.0 → 1.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://badge.fury.io/js/@dangahagan%2Fweather-mcp.svg)](https://www.npmjs.com/package/@dangahagan/weather-mcp)
4
4
  [![MCP Registry](https://img.shields.io/badge/MCP-Registry-blue)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.dgahagan/weather-mcp)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
- [![Tests](https://img.shields.io/badge/tests-3%2C481%20passing-brightgreen)](./docs/testing/TEST_SUITE_README.md)
6
+ [![Tests](https://img.shields.io/badge/tests-3%2C541%20passing-brightgreen)](./docs/testing/TEST_SUITE_README.md)
7
7
  [![Node](https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js&logoColor=white)](https://nodejs.org)
8
8
 
9
9
  **Give your AI assistant real weather data — 17 tools, zero API keys, zero signup, zero cost.**
@@ -58,7 +58,7 @@ Choose this one if you want:
58
58
 
59
59
  - **Genuinely free** — every data source is a free public API. No trial that expires, no credit card, no rate-limited "free tier" bait.
60
60
  - **No API keys** — install to first forecast in under a minute. Nothing to configure, nothing to leak into a repo. ([Three optional keys](#optional-api-keys) add extras if you want them; the default configuration needs none.)
61
- - **Fully open source** — MIT licensed, readable TypeScript, 3,481 tests. Audit it, fork it, fix it.
61
+ - **Fully open source** — MIT licensed, readable TypeScript, 3,541 tests. Audit it, fork it, fix it.
62
62
  - **Privacy-respecting** — your queries go directly from your machine to public weather APIs. No middleman server, no telemetry.
63
63
  - **Breadth** — 17 tools covering weather, safety hazards (lightning, floods, wildfires), marine conditions, air quality, and historical data back to 1940. Most weather MCPs stop at forecasts.
64
64
 
@@ -70,11 +70,11 @@ All 17 tools, documented in detail in **[docs/TOOLS.md](./docs/TOOLS.md)**:
70
70
 
71
71
  | Tool | What it does | Coverage |
72
72
  |------|-------------|----------|
73
- | `get_forecast` | Daily/hourly forecasts up to 16 days by coordinates, saved location, or city name (NOAA publishes 7 days daily and ~6.5 days hourly in the US, and says so when you ask for more; `source="openmeteo"` reaches the full range); sunrise/sunset, UV, precipitation probability, optional climate-normals comparison, optional moon phase & twilight almanac, optional five-model agreement comparison When the National Weather Service has a life-threatening alert active for a US point, its warning is surfaced at the top of the response before the report — absence of the banner is not an all-clear, so call `get_alerts` for the authoritative answer | 🌍 Global |
74
- | `get_current_conditions` | Current weather: temperature, wind, humidity, pressure; NOAA station observations in the US (plus heat index/wind chill, snow depth, optional NOAA fire-weather indices), Open-Meteo model data elsewhere (with an optional computed Fosberg fire-weather index), or real airport station observations worldwide with `source="metar"`. Always states the observation's age, and automatically falls back to a fresher nearby station when the nearest one has gone dark. In extreme conditions automatically adds frostbite time-to-onset (computed wind chill) or heat-stress context (estimated WBGT) When the National Weather Service has a life-threatening alert active for a US point, its warning is surfaced at the top of the response before the report — absence of the banner is not an all-clear, so call `get_alerts` for the authoritative answer | 🌍 Global |
73
+ | `get_forecast` | Daily/hourly forecasts up to 16 days by coordinates, saved location, or city name (NOAA publishes 7 days daily and ~6.5 days hourly in the US, and says so when you ask for more; `source="openmeteo"` reaches the full range); sunrise/sunset, UV, precipitation probability, optional climate-normals comparison, optional moon phase & twilight almanac, optional five-model agreement comparison When the National Weather Service has a life-threatening alert active for a point in the United States or an NWS-served territory, its warning is surfaced at the top of the response before the report — absence of the banner is not an all-clear, so call `get_alerts` for the authoritative answer | 🌍 Global |
74
+ | `get_current_conditions` | Current weather: temperature, wind, humidity, pressure; NOAA station observations in the US (plus heat index/wind chill, snow depth, optional NOAA fire-weather indices), Open-Meteo model data elsewhere (with an optional computed Fosberg fire-weather index), or real airport station observations worldwide with `source="metar"`. Always states the observation's age, and automatically falls back to a fresher nearby station when the nearest one has gone dark. In extreme conditions automatically adds frostbite time-to-onset (computed wind chill) or heat-stress context (estimated WBGT) When the National Weather Service has a life-threatening alert active for a point in the United States or an NWS-served territory, its warning is surfaced at the top of the response before the report — absence of the banner is not an all-clear, so call `get_alerts` for the authoritative answer | 🌍 Global |
75
75
  | `get_alerts` | Active watches, warnings, and advisories sorted by severity; official national warnings for the US (NOAA), Canada (ECCC), 38 European countries (MeteoAlarm), India (NDMA SACHET), the Philippines (PAGASA), Indonesia (BMKG), and Japan (JMA) | 🇺🇸 🇨🇦 🇪🇺 🇮🇳 🇵🇭 🇮🇩 🇯🇵 |
76
76
  | `get_historical_weather` | Hourly/daily observations from 1940 to present | 🌍 Global |
77
- | `get_weather_summary` | One-call overview combining current conditions, forecast, and alerts (optionally air quality and lightning); a life-threatening US alert is surfaced once above the whole summary, not once per section | 🌍 Global |
77
+ | `get_weather_summary` | One-call overview combining current conditions, forecast, and alerts (optionally air quality and lightning); a life-threatening NWS alert is surfaced once above the whole summary, not once per section | 🌍 Global |
78
78
  | `search_location` | Geocode place names to coordinates ("Paris" → 48.85, 2.35) | 🌍 Global |
79
79
  | `get_air_quality` | AQI (US/European scales), pollutants, UV index, health guidance; current pollen levels for European locations (or worldwide with an optional key); optional day-grouped forecast up to 7 days with per-day peak AQI and UV | 🌍 Global |
80
80
  | `get_marine_conditions` | Wave height, swell, ocean currents, sea state on WMO Code Table 3700 (Douglas sea scale) with a severity marker and legend — includes Great Lakes and major US bays; forecast up to 16 days | 🌍 Global |
@@ -388,7 +388,7 @@ Being honest about what free public data can and can't do:
388
388
  ```bash
389
389
  npm run build # Compile TypeScript
390
390
  npm run dev # Run in development mode
391
- npm test # Run all 3,481 tests
391
+ npm test # Run all 3,541 tests
392
392
  npm run test:coverage # Coverage report
393
393
  npm run audit # Dependency vulnerability scan
394
394
  ```
@@ -25,9 +25,18 @@ import type { ResolvedLocation } from '../utils/locationResolver.js';
25
25
  *
26
26
  * In order:
27
27
  *
28
- * 1. **US pre-filter.** `country_code` when the resolution path knew one,
29
- * `isInUS` otherwise. NOAA is the only upstream in v1 (D2), so a non-US
30
- * point returns without making any request at all.
28
+ * 1. **NWS-jurisdiction pre-filter.** `country_code` when the resolution path
29
+ * knew one, geography otherwise `isInUS` **or** `isInNwsTerritory`, the
30
+ * latter covering the four territories `isInUS` deliberately leaves out
31
+ * (Guam, the southern Marianas, the USVI, American Samoa). `isInUS` is not
32
+ * widened to absorb them because it backs a *rendered* NWPS coverage claim in
33
+ * `get_river_conditions`, where Puerto Rico is gauged and Guam is not
34
+ * (GOTCHAS G53). The code path is the two sets above, and there are two of
35
+ * them because a code settles `us` and `pr` on its own while the four
36
+ * territory codes must also satisfy `isInNwsTerritory` — `MP` names a
37
+ * territory NWS serves only the southern half of. NOAA is the only upstream
38
+ * in v1 (D2), so a point outside NWS jurisdiction returns without making any
39
+ * request at all.
31
40
  * 2. **One fetch, no retries.** `getAlerts` caches on its own point-keyed
32
41
  * alerts entry with the five-minute alerts TTL (`src/services/noaa.ts`), so a
33
42
  * banner fetch and a real `get_alerts` call within five minutes share one
@@ -41,11 +50,22 @@ import type { ResolvedLocation } from '../utils/locationResolver.js';
41
50
  * 4. **All-or-nothing.** With no critical alert this emits nothing — no header,
42
51
  * no rule, no "no critical alerts" line.
43
52
  *
44
- * **G2 is not tripped by the pre-filter.** `isInUS` is a bounding box, but
45
- * nothing about the box is rendered: a false negative omits a
46
- * positive-assertion-only element and claims nothing, and a false positive (a
47
- * point just over the Canadian border) costs one request that returns no alerts
48
- * and therefore no banner.
53
+ * **G53 is not tripped by the pre-filter.** These are bounding boxes, but
54
+ * nothing about any box is rendered: a false negative omits a
55
+ * positive-assertion-only element and claims nothing.
56
+ *
57
+ * **A false positive is not free, and the old wording here was wrong about it.**
58
+ * A point the CONUS or Hawaii box admits but NWS does not serve — Toronto
59
+ * `43.65, -79.38`; Midway `28.21, -177.38`, which sits inside the Hawaii box —
60
+ * draws **HTTP 400 `Parameter "point" is invalid: out of bounds`**, not a
61
+ * 200-empty collection. `NOAAService.makeRequest` (`noaa.ts:133-138`) logs a
62
+ * `securityEvent` warn and throws `InvalidLocationError`; this module's catch
63
+ * logs a second; and `getAlerts` never caches a failure, so every call repeats
64
+ * both. That cost is known, deferred (it needs either a narrowed shared routing
65
+ * box or a 4xx-branch change in `noaa.ts`, both beyond the banner), and it is
66
+ * the reason `isInNwsTerritory`'s boxes are drawn tightly to the islands rather
67
+ * than generously — unlike `isInGreatBritain`, whose false positive is one cheap
68
+ * Nominatim call.
49
69
  *
50
70
  * @param noaaService The NOAA client; its `getAlerts` is the only method called
51
71
  * @param resolved The already-resolved location, carrying `country_code` when known
@@ -63,8 +83,8 @@ export declare function resolveCriticalAlertBanner(noaaService: NOAAService, res
63
83
  * and error logging at that single site rather than duplicating either here.
64
84
  *
65
85
  * An empty banner attaches nothing at all, so a failure with no critical alert
66
- * — every non-US point, and every US point with nothing life-threatening
67
- * active — is byte-identical to what it was before.
86
+ * — every point outside NWS jurisdiction, and every point inside it with nothing
87
+ * life-threatening active — is byte-identical to what it was before.
68
88
  *
69
89
  * @param error The error being thrown; returned unchanged for `throw` chaining
70
90
  * @param banner The resolved banner, or `''`
@@ -1 +1 @@
1
- {"version":3,"file":"criticalAlertBanner.d.ts","sourceRoot":"","sources":["../../src/handlers/criticalAlertBanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA4BrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAqDjB;AAYD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQnE"}
1
+ {"version":3,"file":"criticalAlertBanner.d.ts","sourceRoot":"","sources":["../../src/handlers/criticalAlertBanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA8ErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CA8DjB;AAYD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQnE"}
@@ -18,7 +18,7 @@
18
18
  * which is pure and zero-I/O. This module is the glue between that and the
19
19
  * service, and holds no display logic of its own.
20
20
  */
21
- import { isInUS } from '../utils/geography.js';
21
+ import { isInUS, isInNwsTerritory } from '../utils/geography.js';
22
22
  import { logger } from '../utils/logger.js';
23
23
  import { formatCriticalAlertBanner, selectCriticalAlert, } from '../utils/criticalAlert.js';
24
24
  /**
@@ -41,14 +41,71 @@ function httpStatusOf(error) {
41
41
  }
42
42
  return undefined;
43
43
  }
44
+ /**
45
+ * Country codes that settle NWS jurisdiction **on their own**, with no geography.
46
+ *
47
+ * Two sets, not one with a special case: a single set whose membership means
48
+ * different things for different members is how the next reader gets it wrong.
49
+ * The names state the rule.
50
+ *
51
+ * `'pr'` belongs **here and not in `NWS_CODE_PLUS_BOX`, and that is a correctness
52
+ * constraint rather than a style one.** Puerto Rico lives in `isInUS`, *not* in
53
+ * `isInNwsTerritory` — the new predicate covers only the four territories `isInUS`
54
+ * leaves out. Pairing `'pr'` with the territory box would therefore evaluate
55
+ * `false` and silently drop the banner for every Open-Meteo-geocoded Puerto Rico
56
+ * request, turning a coverage fix into a coverage regression. Tidying it across is
57
+ * the obvious wrong move; a mutation row in the plan pins it, and a relocation has
58
+ * the same red set as a deletion.
59
+ *
60
+ * `us` also stays code-alone because making it conditional on a box would silently
61
+ * narrow behaviour this change does not touch.
62
+ *
63
+ * **Which provider emits which value** (G48 — a fixture value the live resolver
64
+ * never produces proves nothing). `us` comes from Census (`geocoding.ts:150`,
65
+ * hard-coded), from Nominatim (`geocoding.ts:239` — OSM resolves every US
66
+ * territory to `US` at country zoom, measured in issue #86 and again 2026-09-18),
67
+ * and from saved locations. The ISO territory codes `GU`/`MP`/`VI`/`AS`/`PR` come
68
+ * **only** from the Open-Meteo geocoder (`geocoding.ts:334`), the last provider in
69
+ * both `GeocodingService` orders (`:443`, `:447`), reached when the first two
70
+ * return nothing. So `pr` is reachable on that path and nowhere else.
71
+ *
72
+ * COFA codes (`fm`, `pw`, `mh`) are absent from both sets deliberately: sovereign
73
+ * countries, `/points` answers 500, out of scope until someone asks.
74
+ *
75
+ * Lower-cased, as `NIFC_COVERED_COUNTRIES` is (`wildfireHandler.ts:68`); these live
76
+ * beside their only consumer because they are not geography facts.
77
+ */
78
+ const NWS_CODE_ALONE = new Set(['us', 'pr']);
79
+ /**
80
+ * Territory codes that require `isInNwsTerritory` **as well**.
81
+ *
82
+ * A country code is a *fast path* — a resolved location already knows its country,
83
+ * so the common case costs no geography at all — and a fast path must not admit
84
+ * what the authoritative predicate rejects. `MP` is the one code in either set that
85
+ * spans served and unserved area: it names the whole Northern Marianas while NWS
86
+ * accepts only the southern arc, so `'MP'` deciding alone would re-open, through
87
+ * the Open-Meteo geocoder, exactly the northern-CNMI request the box was drawn to
88
+ * prevent — an uncached HTTP 400 and two `securityEvent` warns at the points the
89
+ * box exists to exclude.
90
+ */
91
+ const NWS_CODE_PLUS_BOX = new Set(['gu', 'mp', 'vi', 'as']);
44
92
  /**
45
93
  * The banner for this point, or `''` — which is every path but one.
46
94
  *
47
95
  * In order:
48
96
  *
49
- * 1. **US pre-filter.** `country_code` when the resolution path knew one,
50
- * `isInUS` otherwise. NOAA is the only upstream in v1 (D2), so a non-US
51
- * point returns without making any request at all.
97
+ * 1. **NWS-jurisdiction pre-filter.** `country_code` when the resolution path
98
+ * knew one, geography otherwise `isInUS` **or** `isInNwsTerritory`, the
99
+ * latter covering the four territories `isInUS` deliberately leaves out
100
+ * (Guam, the southern Marianas, the USVI, American Samoa). `isInUS` is not
101
+ * widened to absorb them because it backs a *rendered* NWPS coverage claim in
102
+ * `get_river_conditions`, where Puerto Rico is gauged and Guam is not
103
+ * (GOTCHAS G53). The code path is the two sets above, and there are two of
104
+ * them because a code settles `us` and `pr` on its own while the four
105
+ * territory codes must also satisfy `isInNwsTerritory` — `MP` names a
106
+ * territory NWS serves only the southern half of. NOAA is the only upstream
107
+ * in v1 (D2), so a point outside NWS jurisdiction returns without making any
108
+ * request at all.
52
109
  * 2. **One fetch, no retries.** `getAlerts` caches on its own point-keyed
53
110
  * alerts entry with the five-minute alerts TTL (`src/services/noaa.ts`), so a
54
111
  * banner fetch and a real `get_alerts` call within five minutes share one
@@ -62,11 +119,22 @@ function httpStatusOf(error) {
62
119
  * 4. **All-or-nothing.** With no critical alert this emits nothing — no header,
63
120
  * no rule, no "no critical alerts" line.
64
121
  *
65
- * **G2 is not tripped by the pre-filter.** `isInUS` is a bounding box, but
66
- * nothing about the box is rendered: a false negative omits a
67
- * positive-assertion-only element and claims nothing, and a false positive (a
68
- * point just over the Canadian border) costs one request that returns no alerts
69
- * and therefore no banner.
122
+ * **G53 is not tripped by the pre-filter.** These are bounding boxes, but
123
+ * nothing about any box is rendered: a false negative omits a
124
+ * positive-assertion-only element and claims nothing.
125
+ *
126
+ * **A false positive is not free, and the old wording here was wrong about it.**
127
+ * A point the CONUS or Hawaii box admits but NWS does not serve — Toronto
128
+ * `43.65, -79.38`; Midway `28.21, -177.38`, which sits inside the Hawaii box —
129
+ * draws **HTTP 400 `Parameter "point" is invalid: out of bounds`**, not a
130
+ * 200-empty collection. `NOAAService.makeRequest` (`noaa.ts:133-138`) logs a
131
+ * `securityEvent` warn and throws `InvalidLocationError`; this module's catch
132
+ * logs a second; and `getAlerts` never caches a failure, so every call repeats
133
+ * both. That cost is known, deferred (it needs either a narrowed shared routing
134
+ * box or a 4xx-branch change in `noaa.ts`, both beyond the banner), and it is
135
+ * the reason `isInNwsTerritory`'s boxes are drawn tightly to the islands rather
136
+ * than generously — unlike `isInGreatBritain`, whose false positive is one cheap
137
+ * Nominatim call.
70
138
  *
71
139
  * @param noaaService The NOAA client; its `getAlerts` is the only method called
72
140
  * @param resolved The already-resolved location, carrying `country_code` when known
@@ -75,15 +143,22 @@ function httpStatusOf(error) {
75
143
  */
76
144
  export async function resolveCriticalAlertBanner(noaaService, resolved, timezone) {
77
145
  const { latitude, longitude } = resolved;
78
- // country_code first, isInUS second. A saved or geocoded location already
146
+ // country_code first, geography second. A saved or geocoded location already
79
147
  // knows its country, so the common case costs no geography at all. Casing
80
148
  // follows the upstream source (saved locations store "US", geocoders vary),
81
149
  // hence the case-insensitive compare.
82
- const countryCode = resolved.country_code;
83
- const isUS = typeof countryCode === 'string' && countryCode.length > 0
84
- ? countryCode.toLowerCase() === 'us'
85
- : isInUS(latitude, longitude);
86
- if (!isUS) {
150
+ //
151
+ // The conjunction on the territory arm is not decoration: a code from
152
+ // NWS_CODE_PLUS_BOX must also satisfy the box, because `MP` names a territory
153
+ // NWS serves only the southern half of. See the two sets' comments above.
154
+ const countryCode = typeof resolved.country_code === 'string' && resolved.country_code.length > 0
155
+ ? resolved.country_code.toLowerCase()
156
+ : undefined;
157
+ const isNwsServed = countryCode !== undefined
158
+ ? NWS_CODE_ALONE.has(countryCode) ||
159
+ (NWS_CODE_PLUS_BOX.has(countryCode) && isInNwsTerritory(latitude, longitude))
160
+ : isInUS(latitude, longitude) || isInNwsTerritory(latitude, longitude);
161
+ if (!isNwsServed) {
87
162
  return '';
88
163
  }
89
164
  try {
@@ -138,8 +213,8 @@ const CRITICAL_ALERT_BANNER = Symbol.for('weather-mcp.critical-alert-banner');
138
213
  * and error logging at that single site rather than duplicating either here.
139
214
  *
140
215
  * An empty banner attaches nothing at all, so a failure with no critical alert
141
- * — every non-US point, and every US point with nothing life-threatening
142
- * active — is byte-identical to what it was before.
216
+ * — every point outside NWS jurisdiction, and every point inside it with nothing
217
+ * life-threatening active — is byte-identical to what it was before.
143
218
  *
144
219
  * @param error The error being thrown; returned unchanged for `throw` chaining
145
220
  * @param banner The resolved banner, or `''`
@@ -1 +1 @@
1
- {"version":3,"file":"criticalAlertBanner.js","sourceRoot":"","sources":["../../src/handlers/criticalAlertBanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"criticalAlertBanner.js","sourceRoot":"","sources":["../../src/handlers/criticalAlertBanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EACL,yBAAyB,EACzB,mBAAmB,GAEpB,MAAM,2BAA2B,CAAC;AAEnC;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,MAAM,GAAG,KAAkE,CAAC;IAClF,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,UAAU,CAAC;IAC3B,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,QAAQ,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;IAChC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,cAAc,GAAwB,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAElE;;;;;;;;;;;GAWG;AACH,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,WAAwB,EACxB,QAA0B,EAC1B,QAAiB;IAEjB,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAC;IAEzC,6EAA6E;IAC7E,0EAA0E;IAC1E,4EAA4E;IAC5E,sCAAsC;IACtC,EAAE;IACF,sEAAsE;IACtE,8EAA8E;IAC9E,0EAA0E;IAC1E,MAAM,WAAW,GACf,OAAO,QAAQ,CAAC,YAAY,KAAK,QAAQ,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;QAC3E,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE;QACrC,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,WAAW,GACf,WAAW,KAAK,SAAS;QACvB,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC;YAC/B,CAAC,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC/E,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE3E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QAEtE,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,qEAAqE;QACrE,0EAA0E;QAC1E,uCAAuC;QACvC,MAAM,UAAU,GAA6B,QAAQ,CAAC,GAAG,CACvD,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,CAA2B,CACnE,CAAC;QAEF,OAAO,yBAAyB,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,yEAAyE;QACzE,kEAAkE;QAClE,EAAE;QACF,mEAAmE;QACnE,0EAA0E;QAC1E,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,yEAAyE;QACzE,oDAAoD;QACpD,MAAM,CAAC,IAAI,CAAC,0DAA0D,EAAE;YACtE,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,IAAI;YACnB,SAAS,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YACtE,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,qBAAqB,GAAG,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,+BAA+B,CAAC,KAAc,EAAE,MAAc;IAC5E,IAAI,MAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACzD,KAAiC,CAAC,qBAAqB,CAAC,GAAG,MAAM,CAAC;IACrE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACzD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,MAAM,GAAI,KAAiC,CAAC,qBAAqB,CAAC,CAAC;QACzE,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -76,7 +76,7 @@ export declare function getMajorCoastalBayRegions(): GeographicRegion[];
76
76
  */
77
77
  export declare function getCountryFromCoordinates(lat: number, lon: number): string;
78
78
  /**
79
- * Determine if coordinates are within the United States (including Alaska, Hawaii, and territories)
79
+ * Determine if coordinates are within the United States (including Alaska, Hawaii and Puerto Rico; the other NWS-served territories are `isInNwsTerritory`)
80
80
  * Uses bounding box approach for simplicity
81
81
  * @param latitude Latitude coordinate
82
82
  * @param longitude Longitude coordinate
@@ -129,5 +129,69 @@ export declare function isInUS(latitude: number, longitude: number): boolean;
129
129
  * @returns True if coordinates fall within Great Britain's generous routing box
130
130
  */
131
131
  export declare function isInGreatBritain(latitude: number, longitude: number): boolean;
132
+ /**
133
+ * Determine if coordinates fall within one of the NWS-served US territories that
134
+ * `isInUS` deliberately leaves out — Guam, the Northern Mariana Islands (southern
135
+ * arc only), the US Virgin Islands and American Samoa.
136
+ *
137
+ * It answers exactly one question: **will api.weather.gov accept an alerts point
138
+ * here?** Not "is this the United States", not "does NWS forecast here" (it reports
139
+ * no `gridId` for American Samoa at all), and not "does any other service cover
140
+ * this place".
141
+ *
142
+ * This function is **routing only and NEVER renders.** No sentence in any tool
143
+ * output may be derived from it. Its one consumer is the critical-alert banner's
144
+ * pre-filter in `src/handlers/criticalAlertBanner.ts`, which uses it to decide
145
+ * whether one `getAlerts` call is worth making. See GOTCHAS G53: promoting a
146
+ * routing heuristic to a rendered claim inherits every edge the heuristic was
147
+ * previously allowed to get wrong. The moment a rendered sentence names a
148
+ * territory off this predicate, every box below owes a fresh audit against the
149
+ * jurisdiction that sentence names.
150
+ *
151
+ * **Why these boxes are drawn tightly to the islands, which is the opposite of
152
+ * `isInGreatBritain`'s posture.** There, a false positive costs one cheap
153
+ * Nominatim call, so the boxes are deliberately generous. Here a false positive
154
+ * costs an HTTP 400 `Parameter "point" is invalid: out of bounds` from
155
+ * api.weather.gov, which `NOAAService.makeRequest` turns into an
156
+ * `InvalidLocationError` after its own `securityEvent: true` warn; the banner's
157
+ * catch then warns a second time, and `getAlerts` never caches a failure, so every
158
+ * call repeats both. Two security-event log lines per request is the price of a
159
+ * loose edge, so every corner below was probed against the live endpoint on
160
+ * 2026-09-18 and the seams measured. An edge moved "for tidiness" is a 400 or a
161
+ * dropped island. The probe table is in `.devdocs/plan-nws-alert-jurisdiction.md`.
162
+ *
163
+ * **Why Guam and the CNMI are two boxes and not one.** The union's northwest
164
+ * corner, `15.2 N, 144.8 E`, is a measured 400 — the accepted region is not convex
165
+ * there, so a single merged box would admit open ocean NWS rejects.
166
+ *
167
+ * **Why the CNMI box stops at 15.35 N.** NWS rejects every point from 16.0 N north
168
+ * along 145.7 E: Anatahan, Pagan, Agrihan and Farallon de Pajaros are all out of
169
+ * bounds. The northern Marianas are excluded because the service excludes them,
170
+ * not because they were forgotten.
171
+ *
172
+ * **The USVI box admits the British Virgin Islands** (Tortola, Virgin Gorda). NWS
173
+ * answers 200 at those points and nothing here is rendered, so the admission is
174
+ * harmless and deliberate — tightening the box to exclude them would buy nothing
175
+ * and risk clipping St Thomas and St John.
176
+ *
177
+ * **Why American Samoa is two boxes.** The territory is not a rectangle: the main
178
+ * box holds the Tutuila–Manuʻa–Rose band, and Swains Island is a separate pocket
179
+ * ~350 km north. Apia (`−13.83, −171.76`, sovereign Samoa) and the `−168.05`
180
+ * corners outside the band are measured 400s.
181
+ *
182
+ * **`isInUS` must never be widened to absorb these.** That predicate backs a
183
+ * *rendered* coverage claim in `get_river_conditions` (G53), and the two questions
184
+ * have different answers: NWPS gauges Puerto Rico and gauges nothing in Guam, so a
185
+ * widened `isInUS` would tell a caller in Guam that NWPS covers Guam. The two
186
+ * predicates are **disjoint by construction** — the Puerto Rico box's east edge is
187
+ * `−65.2` and the USVI box's west edge is `−65.15`, so they touch without
188
+ * overlapping.
189
+ *
190
+ * @param latitude Latitude coordinate
191
+ * @param longitude Longitude coordinate
192
+ * @returns True if NWS accepts an alerts point at these coordinates in one of the
193
+ * four territories `isInUS` excludes
194
+ */
195
+ export declare function isInNwsTerritory(latitude: number, longitude: number): boolean;
132
196
  export {};
133
197
  //# sourceMappingURL=geography.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"geography.d.ts","sourceRoot":"","sources":["../../src/utils/geography.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOrF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO3F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC;CACjD,CA2BA;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,EAAE,CAEzD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,gBAAgB,EAAE,CAE9D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgD1E;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAgBnE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAY7E"}
1
+ {"version":3,"file":"geography.d.ts","sourceRoot":"","sources":["../../src/utils/geography.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOrF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO3F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC;CACjD,CA2BA;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQtF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,gBAAgB,EAAE,CAEzD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,gBAAgB,EAAE,CAE9D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgD1E;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAgBnE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAY7E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAQ7E"}
@@ -264,7 +264,7 @@ export function getCountryFromCoordinates(lat, lon) {
264
264
  return 'OTHER';
265
265
  }
266
266
  /**
267
- * Determine if coordinates are within the United States (including Alaska, Hawaii, and territories)
267
+ * Determine if coordinates are within the United States (including Alaska, Hawaii and Puerto Rico; the other NWS-served territories are `isInNwsTerritory`)
268
268
  * Uses bounding box approach for simplicity
269
269
  * @param latitude Latitude coordinate
270
270
  * @param longitude Longitude coordinate
@@ -340,4 +340,75 @@ export function isInGreatBritain(latitude, longitude) {
340
340
  const inNorthernScotlandIsles = latitude >= 55.45 && latitude <= 61.05 && longitude >= -9.0 && longitude <= 2.0;
341
341
  return inSouthwestApproaches || inEnglandWalesScotland || inNorthernScotlandIsles;
342
342
  }
343
+ /**
344
+ * Determine if coordinates fall within one of the NWS-served US territories that
345
+ * `isInUS` deliberately leaves out — Guam, the Northern Mariana Islands (southern
346
+ * arc only), the US Virgin Islands and American Samoa.
347
+ *
348
+ * It answers exactly one question: **will api.weather.gov accept an alerts point
349
+ * here?** Not "is this the United States", not "does NWS forecast here" (it reports
350
+ * no `gridId` for American Samoa at all), and not "does any other service cover
351
+ * this place".
352
+ *
353
+ * This function is **routing only and NEVER renders.** No sentence in any tool
354
+ * output may be derived from it. Its one consumer is the critical-alert banner's
355
+ * pre-filter in `src/handlers/criticalAlertBanner.ts`, which uses it to decide
356
+ * whether one `getAlerts` call is worth making. See GOTCHAS G53: promoting a
357
+ * routing heuristic to a rendered claim inherits every edge the heuristic was
358
+ * previously allowed to get wrong. The moment a rendered sentence names a
359
+ * territory off this predicate, every box below owes a fresh audit against the
360
+ * jurisdiction that sentence names.
361
+ *
362
+ * **Why these boxes are drawn tightly to the islands, which is the opposite of
363
+ * `isInGreatBritain`'s posture.** There, a false positive costs one cheap
364
+ * Nominatim call, so the boxes are deliberately generous. Here a false positive
365
+ * costs an HTTP 400 `Parameter "point" is invalid: out of bounds` from
366
+ * api.weather.gov, which `NOAAService.makeRequest` turns into an
367
+ * `InvalidLocationError` after its own `securityEvent: true` warn; the banner's
368
+ * catch then warns a second time, and `getAlerts` never caches a failure, so every
369
+ * call repeats both. Two security-event log lines per request is the price of a
370
+ * loose edge, so every corner below was probed against the live endpoint on
371
+ * 2026-09-18 and the seams measured. An edge moved "for tidiness" is a 400 or a
372
+ * dropped island. The probe table is in `.devdocs/plan-nws-alert-jurisdiction.md`.
373
+ *
374
+ * **Why Guam and the CNMI are two boxes and not one.** The union's northwest
375
+ * corner, `15.2 N, 144.8 E`, is a measured 400 — the accepted region is not convex
376
+ * there, so a single merged box would admit open ocean NWS rejects.
377
+ *
378
+ * **Why the CNMI box stops at 15.35 N.** NWS rejects every point from 16.0 N north
379
+ * along 145.7 E: Anatahan, Pagan, Agrihan and Farallon de Pajaros are all out of
380
+ * bounds. The northern Marianas are excluded because the service excludes them,
381
+ * not because they were forgotten.
382
+ *
383
+ * **The USVI box admits the British Virgin Islands** (Tortola, Virgin Gorda). NWS
384
+ * answers 200 at those points and nothing here is rendered, so the admission is
385
+ * harmless and deliberate — tightening the box to exclude them would buy nothing
386
+ * and risk clipping St Thomas and St John.
387
+ *
388
+ * **Why American Samoa is two boxes.** The territory is not a rectangle: the main
389
+ * box holds the Tutuila–Manuʻa–Rose band, and Swains Island is a separate pocket
390
+ * ~350 km north. Apia (`−13.83, −171.76`, sovereign Samoa) and the `−168.05`
391
+ * corners outside the band are measured 400s.
392
+ *
393
+ * **`isInUS` must never be widened to absorb these.** That predicate backs a
394
+ * *rendered* coverage claim in `get_river_conditions` (G53), and the two questions
395
+ * have different answers: NWPS gauges Puerto Rico and gauges nothing in Guam, so a
396
+ * widened `isInUS` would tell a caller in Guam that NWPS covers Guam. The two
397
+ * predicates are **disjoint by construction** — the Puerto Rico box's east edge is
398
+ * `−65.2` and the USVI box's west edge is `−65.15`, so they touch without
399
+ * overlapping.
400
+ *
401
+ * @param latitude Latitude coordinate
402
+ * @param longitude Longitude coordinate
403
+ * @returns True if NWS accepts an alerts point at these coordinates in one of the
404
+ * four territories `isInUS` excludes
405
+ */
406
+ export function isInNwsTerritory(latitude, longitude) {
407
+ const inGuam = latitude >= 13.2 && latitude <= 13.7 && longitude >= 144.6 && longitude <= 145.0;
408
+ const inMarianasSouthernArc = latitude >= 14.05 && latitude <= 15.35 && longitude >= 145.05 && longitude <= 145.9;
409
+ const inVirginIslands = latitude >= 17.6 && latitude <= 18.45 && longitude >= -65.15 && longitude <= -64.5;
410
+ const inAmericanSamoaMain = latitude >= -14.65 && latitude <= -14.05 && longitude >= -171.0 && longitude <= -168.05;
411
+ const inSwainsIsland = latitude >= -11.2 && latitude <= -10.95 && longitude >= -171.2 && longitude <= -170.95;
412
+ return inGuam || inMarianasSouthernArc || inVirginIslands || inAmericanSamoaMain || inSwainsIsland;
413
+ }
343
414
  //# sourceMappingURL=geography.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"geography.js","sourceRoot":"","sources":["../../src/utils/geography.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"geography.js","sourceRoot":"","sources":["../../src/utils/geography.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangahagan/weather-mcp",
3
- "version": "1.31.0",
3
+ "version": "1.31.1",
4
4
  "description": "MCP server giving AI assistants 17 weather tools with zero API keys: global forecasts, current conditions, alerts, air quality, marine conditions, lightning detection, radar imagery, river levels, wildfire tracking, and historical weather back to 1940. Built entirely on free public APIs (NOAA, Open-Meteo, USGS, NIFC).",
5
5
  "mcpName": "io.github.dgahagan/weather-mcp",
6
6
  "main": "dist/index.js",