@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.
- package/CLAUDE.md +309 -0
- package/Dockerfile +99 -0
- package/LICENSE +190 -0
- package/README.md +249 -0
- package/dist/config/server-config.d.ts +12 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +19 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/resources/definitions/alert-types.resource.d.ts +7 -0
- package/dist/mcp-server/resources/definitions/alert-types.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/alert-types.resource.js +27 -0
- package/dist/mcp-server/resources/definitions/alert-types.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/index.d.ts +6 -0
- package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/index.js +6 -0
- package/dist/mcp-server/resources/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/find-stations.tool.d.ts +22 -0
- package/dist/mcp-server/tools/definitions/find-stations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/find-stations.tool.js +60 -0
- package/dist/mcp-server/tools/definitions/find-stations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-forecast.tool.d.ts +33 -0
- package/dist/mcp-server/tools/definitions/get-forecast.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-forecast.tool.js +125 -0
- package/dist/mcp-server/tools/definitions/get-forecast.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-observations.tool.d.ts +30 -0
- package/dist/mcp-server/tools/definitions/get-observations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-observations.tool.js +177 -0
- package/dist/mcp-server/tools/definitions/get-observations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +10 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +10 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/list-alert-types.tool.d.ts +10 -0
- package/dist/mcp-server/tools/definitions/list-alert-types.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/list-alert-types.tool.js +28 -0
- package/dist/mcp-server/tools/definitions/list-alert-types.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts +51 -0
- package/dist/mcp-server/tools/definitions/search-alerts.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/search-alerts.tool.js +242 -0
- package/dist/mcp-server/tools/definitions/search-alerts.tool.js.map +1 -0
- package/dist/mcp-server/tools/format-utils.d.ts +11 -0
- package/dist/mcp-server/tools/format-utils.d.ts.map +1 -0
- package/dist/mcp-server/tools/format-utils.js +27 -0
- package/dist/mcp-server/tools/format-utils.js.map +1 -0
- package/dist/services/nws/nws-service.d.ts +62 -0
- package/dist/services/nws/nws-service.d.ts.map +1 -0
- package/dist/services/nws/nws-service.js +372 -0
- package/dist/services/nws/nws-service.js.map +1 -0
- package/dist/services/nws/types.d.ts +96 -0
- package/dist/services/nws/types.d.ts.map +1 -0
- package/dist/services/nws/types.js +6 -0
- package/dist/services/nws/types.js.map +1 -0
- package/package.json +82 -0
- 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
|
+
[](https://www.npmjs.com/package/@cyanheads/nws-weather-mcp-server) [](./CHANGELOG.md) [](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) [](https://modelcontextprotocol.io/)
|
|
10
|
+
|
|
11
|
+
[](./LICENSE) [](https://www.typescriptlang.org/) [](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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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
|