@cyanheads/nws-weather-mcp-server 0.3.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.
Files changed (58) hide show
  1. package/CLAUDE.md +309 -0
  2. package/Dockerfile +99 -0
  3. package/LICENSE +190 -0
  4. package/README.md +249 -0
  5. package/dist/config/server-config.d.ts +12 -0
  6. package/dist/config/server-config.d.ts.map +1 -0
  7. package/dist/config/server-config.js +19 -0
  8. package/dist/config/server-config.js.map +1 -0
  9. package/dist/index.d.ts +7 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +23 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/mcp-server/resources/definitions/alert-types.resource.d.ts +7 -0
  14. package/dist/mcp-server/resources/definitions/alert-types.resource.d.ts.map +1 -0
  15. package/dist/mcp-server/resources/definitions/alert-types.resource.js +27 -0
  16. package/dist/mcp-server/resources/definitions/alert-types.resource.js.map +1 -0
  17. package/dist/mcp-server/resources/definitions/index.d.ts +6 -0
  18. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
  19. package/dist/mcp-server/resources/definitions/index.js +6 -0
  20. package/dist/mcp-server/resources/definitions/index.js.map +1 -0
  21. package/dist/mcp-server/tools/definitions/find-stations.tool.d.ts +22 -0
  22. package/dist/mcp-server/tools/definitions/find-stations.tool.d.ts.map +1 -0
  23. package/dist/mcp-server/tools/definitions/find-stations.tool.js +60 -0
  24. package/dist/mcp-server/tools/definitions/find-stations.tool.js.map +1 -0
  25. package/dist/mcp-server/tools/definitions/get-forecast.tool.d.ts +33 -0
  26. package/dist/mcp-server/tools/definitions/get-forecast.tool.d.ts.map +1 -0
  27. package/dist/mcp-server/tools/definitions/get-forecast.tool.js +125 -0
  28. package/dist/mcp-server/tools/definitions/get-forecast.tool.js.map +1 -0
  29. package/dist/mcp-server/tools/definitions/get-observations.tool.d.ts +30 -0
  30. package/dist/mcp-server/tools/definitions/get-observations.tool.d.ts.map +1 -0
  31. package/dist/mcp-server/tools/definitions/get-observations.tool.js +177 -0
  32. package/dist/mcp-server/tools/definitions/get-observations.tool.js.map +1 -0
  33. package/dist/mcp-server/tools/definitions/index.d.ts +10 -0
  34. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  35. package/dist/mcp-server/tools/definitions/index.js +10 -0
  36. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  37. package/dist/mcp-server/tools/definitions/list-alert-types.tool.d.ts +10 -0
  38. package/dist/mcp-server/tools/definitions/list-alert-types.tool.d.ts.map +1 -0
  39. package/dist/mcp-server/tools/definitions/list-alert-types.tool.js +28 -0
  40. package/dist/mcp-server/tools/definitions/list-alert-types.tool.js.map +1 -0
  41. package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts +51 -0
  42. package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts.map +1 -0
  43. package/dist/mcp-server/tools/definitions/search-alerts.tool.js +242 -0
  44. package/dist/mcp-server/tools/definitions/search-alerts.tool.js.map +1 -0
  45. package/dist/mcp-server/tools/format-utils.d.ts +11 -0
  46. package/dist/mcp-server/tools/format-utils.d.ts.map +1 -0
  47. package/dist/mcp-server/tools/format-utils.js +27 -0
  48. package/dist/mcp-server/tools/format-utils.js.map +1 -0
  49. package/dist/services/nws/nws-service.d.ts +62 -0
  50. package/dist/services/nws/nws-service.d.ts.map +1 -0
  51. package/dist/services/nws/nws-service.js +372 -0
  52. package/dist/services/nws/nws-service.js.map +1 -0
  53. package/dist/services/nws/types.d.ts +96 -0
  54. package/dist/services/nws/types.d.ts.map +1 -0
  55. package/dist/services/nws/types.js +6 -0
  56. package/dist/services/nws/types.js.map +1 -0
  57. package/package.json +82 -0
  58. package/server.json +101 -0
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ <div align="center">
2
+ <h1>@cyanheads/nws-weather-mcp-server</h1>
3
+ <p><b>Real-time US weather data via the National Weather Service API. Forecasts, alerts, and observations with zero auth.</b></p>
4
+ <p><b>5 Tools · 1 Resource</b></p>
5
+ </div>
6
+
7
+ <div align="center">
8
+
9
+ [![npm](https://img.shields.io/npm/v/@cyanheads/nws-weather-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/nws-weather-mcp-server) [![Version](https://img.shields.io/badge/Version-0.3.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![Framework](https://img.shields.io/badge/Built%20on-@cyanheads/mcp--ts--core-259?style=flat-square)](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.29.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/)
10
+
11
+ [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-^5.9.3-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.2+-blueviolet.svg?style=flat-square)](https://bun.sh/)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ ## Tools
18
+
19
+ Five tools for real-time US weather data:
20
+
21
+ | Tool | Description |
22
+ |:----------|:------------|
23
+ | `nws_get_forecast` | 7-day or hourly forecast for coordinates. Resolves NWS grid internally. |
24
+ | `nws_search_alerts` | Active weather alerts filtered by area, point, zone, event, severity. |
25
+ | `nws_get_observations` | Current conditions by coordinates (nearest station) or station ID. |
26
+ | `nws_find_stations` | Nearby observation stations sorted by distance with bearing. |
27
+ | `nws_list_alert_types` | All valid alert event type names for filter discovery. |
28
+
29
+ ### `nws_get_forecast`
30
+
31
+ Get the weather forecast for a US location.
32
+
33
+ - Default returns named 12-hour periods (14 total, ~7 days)
34
+ - Hourly mode returns up to 156 one-hour periods with dewpoint and humidity
35
+ - Coordinates resolve to NWS grid internally via `/points` endpoint
36
+
37
+ ---
38
+
39
+ ### `nws_search_alerts`
40
+
41
+ Search active weather alerts with flexible filtering.
42
+
43
+ - Filter by area (state/territory/marine codes), point (lat,lon), zone, event type, severity, urgency, certainty
44
+ - National search when no filters provided
45
+ - Results capped at 25 with truncation notice and guidance to narrow filters
46
+ - Validates area codes and point format before API call
47
+
48
+ ---
49
+
50
+ ### `nws_get_observations`
51
+
52
+ Current measured conditions from a weather station.
53
+
54
+ - Look up by coordinates (finds nearest station) or station ID directly
55
+ - Dual-unit display: F/C, mph/km/h, inHg/hPa, mi/km
56
+ - Warns when most measurements are unavailable from a station
57
+
58
+ ---
59
+
60
+ ### `nws_find_stations`
61
+
62
+ Discover nearby observation stations.
63
+
64
+ - Sorted by haversine distance from query point
65
+ - Returns distance (km) and compass bearing
66
+ - Includes zone codes, elevation, time zone
67
+ - Useful for finding station IDs for `nws_get_observations`
68
+
69
+ ---
70
+
71
+ ### `nws_list_alert_types`
72
+
73
+ List all valid NWS alert event type names.
74
+
75
+ - Returns the full set of event types the NWS API recognizes (e.g., "Tornado Warning", "Heat Advisory")
76
+ - Use to discover valid values for the `event` filter in `nws_search_alerts`
77
+
78
+ ## Resources
79
+
80
+ | URI Pattern | Description |
81
+ |:------------|:------------|
82
+ | `nws://alert-types` | Static list of all valid NWS alert event type names. |
83
+
84
+ ## Features
85
+
86
+ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core):
87
+
88
+ - Declarative tool definitions — single file per tool, framework handles registration and validation
89
+ - Unified error handling across all tools
90
+ - Pluggable auth (`none`, `jwt`, `oauth`)
91
+ - Swappable storage backends: `in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`
92
+ - Structured logging with optional OpenTelemetry tracing
93
+ - Runs locally (stdio/HTTP) or on Cloudflare Workers from the same codebase
94
+
95
+ NWS-specific:
96
+
97
+ - Zero-auth access to the NWS API — no API keys required
98
+ - Automatic coordinate-to-grid resolution with caching (1h TTL)
99
+ - Retry with backoff for transient NWS API failures
100
+ - Dual-unit display for observations (F/C, mph/km/h, inHg/hPa, mi/km)
101
+ - Continental US, Alaska, Hawaii, and US territories coverage
102
+
103
+ ## Getting started
104
+
105
+ Add the following to your MCP client configuration file.
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "nws-weather": {
111
+ "type": "stdio",
112
+ "command": "bunx",
113
+ "args": ["@cyanheads/nws-weather-mcp-server@latest"],
114
+ "env": {
115
+ "MCP_TRANSPORT_TYPE": "stdio",
116
+ "MCP_LOG_LEVEL": "info"
117
+ }
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ Or with npx (no Bun required):
124
+
125
+ ```json
126
+ {
127
+ "mcpServers": {
128
+ "nws-weather": {
129
+ "type": "stdio",
130
+ "command": "npx",
131
+ "args": ["-y", "@cyanheads/nws-weather-mcp-server@latest"],
132
+ "env": {
133
+ "MCP_TRANSPORT_TYPE": "stdio",
134
+ "MCP_LOG_LEVEL": "info"
135
+ }
136
+ }
137
+ }
138
+ }
139
+ ```
140
+
141
+ Or with Docker:
142
+
143
+ ```json
144
+ {
145
+ "mcpServers": {
146
+ "nws-weather": {
147
+ "type": "stdio",
148
+ "command": "docker",
149
+ "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/nws-weather-mcp-server:latest"]
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ For Streamable HTTP, set the transport and start the server:
156
+
157
+ ```sh
158
+ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
159
+ # Server listens at http://localhost:3010/mcp
160
+ ```
161
+
162
+ ### Prerequisites
163
+
164
+ - [Node.js v22+](https://nodejs.org/) or [Bun v1.2+](https://bun.sh/)
165
+
166
+ ### Installation
167
+
168
+ 1. **Clone the repository:**
169
+
170
+ ```sh
171
+ git clone https://github.com/cyanheads/nws-weather-mcp-server.git
172
+ ```
173
+
174
+ 2. **Navigate into the directory:**
175
+
176
+ ```sh
177
+ cd nws-weather-mcp-server
178
+ ```
179
+
180
+ 3. **Install dependencies:**
181
+
182
+ ```sh
183
+ bun install
184
+ ```
185
+
186
+ ## Configuration
187
+
188
+ | Variable | Description | Default |
189
+ |:---------|:------------|:--------|
190
+ | `NWS_USER_AGENT` | User-Agent for NWS API requests. The API requires this header. | `(nws-weather-mcp-server, ...)` |
191
+ | `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
192
+ | `MCP_HTTP_PORT` | Port for HTTP server. | `3010` |
193
+ | `MCP_HTTP_HOST` | Hostname for HTTP server. | `127.0.0.1` |
194
+ | `MCP_LOG_LEVEL` | Log level: `debug`, `info`, `notice`, `warning`, `error`. | `info` |
195
+
196
+ See [`.env.example`](.env.example) for the full list including auth, storage, and OpenTelemetry options.
197
+
198
+ ## Running the server
199
+
200
+ ### Local development
201
+
202
+ - **Build and run the production version:**
203
+
204
+ ```sh
205
+ # One-time build
206
+ bun run rebuild
207
+
208
+ # Run the built server
209
+ bun run start:http
210
+ # or
211
+ bun run start:stdio
212
+ ```
213
+
214
+ - **Run checks and tests:**
215
+
216
+ ```sh
217
+ bun run devcheck # Lints, formats, type-checks
218
+ bun run test # Runs test suite
219
+ ```
220
+
221
+ ## Project structure
222
+
223
+ | Directory | Purpose |
224
+ |:----------|:--------|
225
+ | `src/mcp-server/tools/definitions/` | Tool definitions (`*.tool.ts`). |
226
+ | `src/mcp-server/resources/definitions/` | Resource definitions (`*.resource.ts`). |
227
+ | `src/services/nws/` | NWS API client and response types. |
228
+ | `src/config/` | Environment variable parsing and validation with Zod. |
229
+
230
+ ## Development guide
231
+
232
+ See [`CLAUDE.md`](./CLAUDE.md) for development guidelines and architectural rules. The short version:
233
+
234
+ - Handlers throw, framework catches — no `try/catch` in tool logic
235
+ - Use `ctx.log` for domain-specific logging, `ctx.state` for storage
236
+ - Add new tools/resources to the barrel exports and the `createApp()` arrays in `src/index.ts`
237
+
238
+ ## Contributing
239
+
240
+ Issues and pull requests are welcome. Run checks before submitting:
241
+
242
+ ```sh
243
+ bun run devcheck
244
+ bun run test
245
+ ```
246
+
247
+ ## License
248
+
249
+ Apache-2.0 — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @fileoverview Server-specific configuration for nws-weather-mcp-server.
3
+ * @module config/server-config
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ declare const ServerConfigSchema: z.ZodObject<{
7
+ userAgent: z.ZodDefault<z.ZodString>;
8
+ }, z.core.$strip>;
9
+ export type ServerConfig = z.infer<typeof ServerConfigSchema>;
10
+ export declare function getServerConfig(): ServerConfig;
11
+ export {};
12
+ //# sourceMappingURL=server-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,QAAA,MAAM,kBAAkB;;iBAKtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wBAAgB,eAAe,IAAI,YAAY,CAK9C"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Server-specific configuration for nws-weather-mcp-server.
3
+ * @module config/server-config
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ const ServerConfigSchema = z.object({
7
+ userAgent: z
8
+ .string()
9
+ .default('(nws-weather-mcp-server, github.com/cyanheads/nws-weather-mcp-server)')
10
+ .describe('User-Agent header for NWS API requests. Required by the API — 403 without it.'),
11
+ });
12
+ let _config;
13
+ export function getServerConfig() {
14
+ _config ??= ServerConfigSchema.parse({
15
+ userAgent: process.env.NWS_USER_AGENT,
16
+ });
17
+ return _config;
18
+ }
19
+ //# sourceMappingURL=server-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,OAAO,CAAC,uEAAuE,CAAC;SAChF,QAAQ,CAAC,+EAA+E,CAAC;CAC7F,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,kBAAkB,CAAC,KAAK,CAAC;QACnC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;KACtC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview nws-weather-mcp-server MCP server entry point.
4
+ * @module index
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview nws-weather-mcp-server MCP server entry point.
4
+ * @module index
5
+ */
6
+ import { createApp } from '@cyanheads/mcp-ts-core';
7
+ import { alertTypesResource } from './mcp-server/resources/definitions/index.js';
8
+ import { findStationsTool, getForecastTool, getObservationsTool, listAlertTypesTool, searchAlertsTool, } from './mcp-server/tools/definitions/index.js';
9
+ import { initNwsService } from './services/nws/nws-service.js';
10
+ await createApp({
11
+ tools: [
12
+ getForecastTool,
13
+ searchAlertsTool,
14
+ getObservationsTool,
15
+ findStationsTool,
16
+ listAlertTypesTool,
17
+ ],
18
+ resources: [alertTypesResource],
19
+ setup() {
20
+ initNwsService();
21
+ },
22
+ });
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,6CAA6C,CAAC;AACjF,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,MAAM,SAAS,CAAC;IACd,KAAK,EAAE;QACL,eAAe;QACf,gBAAgB;QAChB,mBAAmB;QACnB,gBAAgB;QAChB,kBAAkB;KACnB;IACD,SAAS,EAAE,CAAC,kBAAkB,CAAC;IAC/B,KAAK;QACH,cAAc,EAAE,CAAC;IACnB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @fileoverview Resource: nws://alert-types — static list of valid NWS alert event type names.
3
+ * @module mcp-server/resources/definitions/alert-types
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ export declare const alertTypesResource: import("@cyanheads/mcp-ts-core").ResourceDefinition<z.ZodObject<{}, z.core.$strip>, undefined>;
7
+ //# sourceMappingURL=alert-types.resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert-types.resource.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/alert-types.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAY,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGrD,eAAO,MAAM,kBAAkB,gGAsB7B,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @fileoverview Resource: nws://alert-types — static list of valid NWS alert event type names.
3
+ * @module mcp-server/resources/definitions/alert-types
4
+ */
5
+ import { resource, z } from '@cyanheads/mcp-ts-core';
6
+ import { getNwsService } from '../../../services/nws/nws-service.js';
7
+ export const alertTypesResource = resource('nws://alert-types', {
8
+ name: 'NWS Alert Event Types',
9
+ description: 'Static list of all valid NWS alert event type names. Useful reference when constructing event filters for nws_search_alerts.',
10
+ mimeType: 'application/json',
11
+ params: z.object({}),
12
+ async handler(_params, ctx) {
13
+ const types = await getNwsService().listAlertTypes(ctx);
14
+ return { count: types.length, eventTypes: [...types].sort() };
15
+ },
16
+ list: async () => ({
17
+ resources: [
18
+ {
19
+ uri: 'nws://alert-types',
20
+ name: 'NWS Alert Event Types',
21
+ description: 'All valid alert event type names for filtering.',
22
+ mimeType: 'application/json',
23
+ },
24
+ ],
25
+ }),
26
+ });
27
+ //# sourceMappingURL=alert-types.resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert-types.resource.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/alert-types.resource.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,mBAAmB,EAAE;IAC9D,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,8HAA8H;IAChI,QAAQ,EAAE,kBAAkB;IAC5B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IAEpB,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG;QACxB,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QACxD,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IAChE,CAAC;IAED,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QACjB,SAAS,EAAE;YACT;gBACE,GAAG,EAAE,mBAAmB;gBACxB,IAAI,EAAE,uBAAuB;gBAC7B,WAAW,EAAE,iDAAiD;gBAC9D,QAAQ,EAAE,kBAAkB;aAC7B;SACF;KACF,CAAC;CACH,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview Barrel export for all resource definitions.
3
+ * @module mcp-server/resources/definitions
4
+ */
5
+ export { alertTypesResource } from './alert-types.resource.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview Barrel export for all resource definitions.
3
+ * @module mcp-server/resources/definitions
4
+ */
5
+ export { alertTypesResource } from './alert-types.resource.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp-server/resources/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @fileoverview Tool: nws_find_stations — finds nearby weather observation stations.
3
+ * @module mcp-server/tools/definitions/find-stations
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ export declare const findStationsTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
7
+ latitude: z.ZodNumber;
8
+ longitude: z.ZodNumber;
9
+ limit: z.ZodDefault<z.ZodNumber>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ stations: z.ZodArray<z.ZodObject<{
12
+ stationId: z.ZodString;
13
+ name: z.ZodString;
14
+ distance: z.ZodNumber;
15
+ bearing: z.ZodString;
16
+ elevation: z.ZodNullable<z.ZodNumber>;
17
+ timeZone: z.ZodString;
18
+ county: z.ZodString;
19
+ forecastZone: z.ZodString;
20
+ }, z.core.$strip>>;
21
+ }, z.core.$strip>>;
22
+ //# sourceMappingURL=find-stations.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-stations.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/find-stations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAGjD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;kBAuE3B,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @fileoverview Tool: nws_find_stations — finds nearby weather observation stations.
3
+ * @module mcp-server/tools/definitions/find-stations
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { getNwsService } from '../../../services/nws/nws-service.js';
7
+ export const findStationsTool = tool('nws_find_stations', {
8
+ description: '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.',
9
+ annotations: { readOnlyHint: true },
10
+ input: z.object({
11
+ latitude: z.number().min(-90).max(90).describe('Center latitude for proximity search.'),
12
+ longitude: z.number().min(-180).max(180).describe('Center longitude for proximity search.'),
13
+ limit: z.number().int().min(1).max(50).default(10).describe('Max stations to return (1-50).'),
14
+ }),
15
+ output: z.object({
16
+ stations: z
17
+ .array(z.object({
18
+ stationId: z.string().describe('Station identifier (e.g., "KSEA")'),
19
+ name: z.string().describe('Station name'),
20
+ distance: z.number().describe('Distance from query point in km'),
21
+ bearing: z.string().describe('Compass bearing from query point (e.g., "NW")'),
22
+ elevation: z.number().nullable().describe('Elevation in meters'),
23
+ timeZone: z.string().describe('IANA time zone'),
24
+ county: z.string().describe('County zone code (e.g., "WAC033")'),
25
+ forecastZone: z.string().describe('Forecast zone code (e.g., "WAZ315")'),
26
+ }))
27
+ .describe('Nearby stations sorted by distance'),
28
+ }),
29
+ async handler(input, ctx) {
30
+ const result = await getNwsService().findStations(input.latitude, input.longitude, input.limit, ctx);
31
+ return {
32
+ stations: result.stations.map((s) => ({
33
+ stationId: s.stationId,
34
+ name: s.name,
35
+ distance: s.distance,
36
+ bearing: s.bearing,
37
+ elevation: s.elevation.value != null ? Math.round(s.elevation.value) : null,
38
+ timeZone: s.timeZone,
39
+ county: s.county,
40
+ forecastZone: s.forecastZone,
41
+ })),
42
+ };
43
+ },
44
+ format: (result) => {
45
+ if (result.stations.length === 0) {
46
+ return [{ type: 'text', text: 'No stations found near this location.' }];
47
+ }
48
+ const lines = [
49
+ `## ${result.stations.length} Nearby Station${result.stations.length > 1 ? 's' : ''}\n`,
50
+ ];
51
+ lines.push('| Station | Name | Distance | Bearing | Elevation | Time Zone |');
52
+ lines.push('|:--------|:-----|:---------|:--------|:----------|:----------|');
53
+ for (const s of result.stations) {
54
+ const elev = s.elevation != null ? `${Math.round(s.elevation)}m` : '—';
55
+ lines.push(`| ${s.stationId} | ${s.name} | ${s.distance} km | ${s.bearing} | ${elev} | ${s.timeZone} |`);
56
+ }
57
+ return [{ type: 'text', text: lines.join('\n') }];
58
+ },
59
+ });
60
+ //# sourceMappingURL=find-stations.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-stations.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/find-stations.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @fileoverview Tool: nws_get_forecast — retrieves weather forecast for US coordinates.
3
+ * @module mcp-server/tools/definitions/get-forecast
4
+ */
5
+ import { z } from '@cyanheads/mcp-ts-core';
6
+ export declare const getForecastTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
7
+ latitude: z.ZodNumber;
8
+ longitude: z.ZodNumber;
9
+ hourly: z.ZodDefault<z.ZodBoolean>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ location: z.ZodObject<{
12
+ city: z.ZodString;
13
+ state: z.ZodString;
14
+ office: z.ZodString;
15
+ timeZone: z.ZodString;
16
+ }, z.core.$strip>;
17
+ generatedAt: z.ZodString;
18
+ periods: z.ZodArray<z.ZodObject<{
19
+ name: z.ZodString;
20
+ startTime: z.ZodString;
21
+ endTime: z.ZodString;
22
+ temperature: z.ZodNumber;
23
+ temperatureUnit: z.ZodString;
24
+ windSpeed: z.ZodString;
25
+ windDirection: z.ZodString;
26
+ shortForecast: z.ZodString;
27
+ detailedForecast: z.ZodString;
28
+ precipChance: z.ZodNullable<z.ZodNumber>;
29
+ dewpoint: z.ZodNullable<z.ZodNumber>;
30
+ relativeHumidity: z.ZodNullable<z.ZodNumber>;
31
+ }, z.core.$strip>>;
32
+ }, z.core.$strip>>;
33
+ //# sourceMappingURL=get-forecast.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-forecast.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-forecast.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAgBjD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;kBAkI1B,CAAC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * @fileoverview Tool: nws_get_forecast — retrieves weather forecast for US coordinates.
3
+ * @module mcp-server/tools/definitions/get-forecast
4
+ */
5
+ import { tool, z } from '@cyanheads/mcp-ts-core';
6
+ import { getNwsService } from '../../../services/nws/nws-service.js';
7
+ import { cToF, formatTimestamp, fToC } from '../format-utils.js';
8
+ /** Derive a period label from startTime when name is empty (hourly periods). */
9
+ function periodLabel(name, startTime) {
10
+ if (name)
11
+ return name;
12
+ const d = new Date(startTime);
13
+ if (Number.isNaN(d.getTime()))
14
+ return startTime;
15
+ return d.toLocaleString('en-US', {
16
+ weekday: 'short',
17
+ hour: 'numeric',
18
+ minute: '2-digit',
19
+ });
20
+ }
21
+ export const getForecastTool = tool('nws_get_forecast', {
22
+ description: 'Get the weather forecast for a US location. Returns either named 12-hour periods (default) or hourly breakdowns. Internally resolves coordinates to the NWS grid.',
23
+ annotations: { readOnlyHint: true },
24
+ input: z.object({
25
+ latitude: z
26
+ .number()
27
+ .min(-90)
28
+ .max(90)
29
+ .describe('Latitude in decimal degrees (e.g., 47.6062). Truncated to 4 decimal places.'),
30
+ longitude: z
31
+ .number()
32
+ .min(-180)
33
+ .max(180)
34
+ .describe('Longitude in decimal degrees (e.g., -122.3321). Truncated to 4 decimal places.'),
35
+ hourly: z
36
+ .boolean()
37
+ .default(false)
38
+ .describe('If true, returns hourly forecast (~156 periods) instead of 12-hour named periods (14 periods). Hourly includes dewpoint and relative humidity.'),
39
+ }),
40
+ output: z.object({
41
+ location: z
42
+ .object({
43
+ city: z.string().describe('City name'),
44
+ state: z.string().describe('State name'),
45
+ office: z.string().describe('NWS Weather Forecast Office code'),
46
+ timeZone: z.string().describe('IANA time zone'),
47
+ })
48
+ .describe('Resolved location metadata'),
49
+ generatedAt: z.string().describe('When the forecast was generated (ISO 8601)'),
50
+ periods: z
51
+ .array(z.object({
52
+ name: z.string().describe('Period name (e.g., "Today", "Tonight") or hour label'),
53
+ startTime: z.string().describe('Period start (ISO 8601)'),
54
+ endTime: z.string().describe('Period end (ISO 8601)'),
55
+ temperature: z.number().describe('Temperature value'),
56
+ temperatureUnit: z.string().describe('Temperature unit (F or C)'),
57
+ windSpeed: z.string().describe('Wind speed (e.g., "10 mph")'),
58
+ windDirection: z.string().describe('Wind direction (e.g., "NW")'),
59
+ shortForecast: z.string().describe('Brief forecast (e.g., "Mostly Sunny")'),
60
+ detailedForecast: z.string().describe('Full narrative forecast'),
61
+ precipChance: z.number().nullable().describe('Probability of precipitation (%)'),
62
+ dewpoint: z.number().nullable().describe('Dewpoint in Celsius (hourly only)'),
63
+ relativeHumidity: z.number().nullable().describe('Relative humidity % (hourly only)'),
64
+ }))
65
+ .describe('Forecast periods'),
66
+ }),
67
+ async handler(input, ctx) {
68
+ const result = await getNwsService().getForecast(input.latitude, input.longitude, input.hourly, ctx);
69
+ return {
70
+ location: result.location,
71
+ generatedAt: result.forecast.generatedAt,
72
+ periods: result.forecast.periods.map((p) => ({
73
+ name: p.name,
74
+ startTime: p.startTime,
75
+ endTime: p.endTime,
76
+ temperature: p.temperature,
77
+ temperatureUnit: p.temperatureUnit,
78
+ windSpeed: p.windSpeed,
79
+ windDirection: p.windDirection,
80
+ shortForecast: p.shortForecast,
81
+ detailedForecast: p.detailedForecast,
82
+ precipChance: p.probabilityOfPrecipitation.value,
83
+ dewpoint: p.dewpoint.value != null ? Math.round(p.dewpoint.value * 10) / 10 : null,
84
+ relativeHumidity: p.relativeHumidity.value != null ? Math.round(p.relativeHumidity.value * 10) / 10 : null,
85
+ })),
86
+ };
87
+ },
88
+ format: (result) => {
89
+ const loc = result.location;
90
+ const lines = [
91
+ `## Forecast for ${loc.city}, ${loc.state}`,
92
+ `**Office:** ${loc.office} | **Time Zone:** ${loc.timeZone} | **Generated:** ${formatTimestamp(result.generatedAt)}`,
93
+ '',
94
+ ];
95
+ if (result.periods.length === 0) {
96
+ lines.push('No forecast periods available for this location.');
97
+ return [{ type: 'text', text: lines.join('\n') }];
98
+ }
99
+ const periods = result.periods.slice(0, 48);
100
+ for (const p of periods) {
101
+ const precip = p.precipChance != null ? ` | **Precip:** ${p.precipChance}%` : '';
102
+ const humidity = p.relativeHumidity != null ? ` | **Humidity:** ${p.relativeHumidity}%` : '';
103
+ const dew = p.dewpoint != null
104
+ ? ` | **Dewpoint:** ${cToF(p.dewpoint)}°F (${Math.round(p.dewpoint)}°C)`
105
+ : '';
106
+ lines.push(`### ${periodLabel(p.name, p.startTime)}`);
107
+ const tempDual = p.temperatureUnit === 'F'
108
+ ? `${p.temperature}°F (${fToC(p.temperature)}°C)`
109
+ : `${cToF(p.temperature)}°F (${p.temperature}°C)`;
110
+ lines.push(`**${tempDual}** | **Wind:** ${p.windSpeed} ${p.windDirection}${precip}${humidity}${dew}`);
111
+ if (p.detailedForecast) {
112
+ lines.push(p.detailedForecast);
113
+ }
114
+ else {
115
+ lines.push(p.shortForecast);
116
+ }
117
+ lines.push('');
118
+ }
119
+ if (result.periods.length > 48) {
120
+ lines.push(`_...and ${result.periods.length - 48} more periods (${result.periods.length} total)._`);
121
+ }
122
+ return [{ type: 'text', text: lines.join('\n') }];
123
+ },
124
+ });
125
+ //# sourceMappingURL=get-forecast.tool.js.map