@dangahagan/weather-mcp 1.33.15 → 1.33.16
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 +3 -3
- package/dist/analytics/collector.d.ts +13 -3
- package/dist/analytics/collector.d.ts.map +1 -1
- package/dist/analytics/collector.js +13 -7
- package/dist/analytics/collector.js.map +1 -1
- package/dist/analytics/transport.d.ts +19 -1
- package/dist/analytics/transport.d.ts.map +1 -1
- package/dist/analytics/transport.js +62 -25
- package/dist/analytics/transport.js.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@dangahagan/weather-mcp)
|
|
4
4
|
[](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.dgahagan/weather-mcp)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
-
[](./docs/testing/TEST_SUITE_README.md)
|
|
7
7
|
[](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, 4,
|
|
61
|
+
- **Fully open source** — MIT licensed, readable TypeScript, 4,206 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
|
|
|
@@ -391,7 +391,7 @@ Being honest about what free public data can and can't do:
|
|
|
391
391
|
```bash
|
|
392
392
|
npm run build # Compile TypeScript
|
|
393
393
|
npm run dev # Run in development mode
|
|
394
|
-
npm test # Run all 4,
|
|
394
|
+
npm test # Run all 4,206 tests
|
|
395
395
|
npm run test:coverage # Coverage report
|
|
396
396
|
npm run audit # Dependency vulnerability scan
|
|
397
397
|
```
|
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
* Analytics event collector and batch manager
|
|
3
3
|
* Buffers events in memory and periodically flushes to analytics server
|
|
4
4
|
*/
|
|
5
|
+
import { sendBatch } from './transport.js';
|
|
5
6
|
import { AnalyticsConfig, ToolExecutionMetadata } from './types.js';
|
|
7
|
+
/** Per-call options for `flush` and `shutdown`. Absent means the transport's own default. */
|
|
8
|
+
export interface FlushOptions {
|
|
9
|
+
deadlineMs?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Injectable seams; the default is the real transport. */
|
|
12
|
+
export interface AnalyticsCollectorDeps {
|
|
13
|
+
sendBatch?: typeof sendBatch;
|
|
14
|
+
}
|
|
6
15
|
/**
|
|
7
16
|
* AnalyticsCollector - Manages event buffering and batch sending
|
|
8
17
|
* Implements privacy-first analytics with automatic flushing
|
|
@@ -14,6 +23,7 @@ export declare class AnalyticsCollector {
|
|
|
14
23
|
private sessionId;
|
|
15
24
|
private sequenceNumber;
|
|
16
25
|
private isShuttingDown;
|
|
26
|
+
private readonly sendBatch;
|
|
17
27
|
private consecutiveFailures;
|
|
18
28
|
private circuitOpen;
|
|
19
29
|
private circuitOpenUntil;
|
|
@@ -30,7 +40,7 @@ export declare class AnalyticsCollector {
|
|
|
30
40
|
private recentEventTimestamps;
|
|
31
41
|
private readonly MAX_BUFFER_SIZE;
|
|
32
42
|
private readonly FLUSH_INTERVAL_MS;
|
|
33
|
-
constructor(config: AnalyticsConfig);
|
|
43
|
+
constructor(config: AnalyticsConfig, deps?: AnalyticsCollectorDeps);
|
|
34
44
|
/**
|
|
35
45
|
* Track a tool execution event
|
|
36
46
|
* Fails silently - analytics should never break the application
|
|
@@ -41,7 +51,7 @@ export declare class AnalyticsCollector {
|
|
|
41
51
|
* Called automatically on timer or when buffer is full
|
|
42
52
|
* Implements circuit breaker pattern (3.7)
|
|
43
53
|
*/
|
|
44
|
-
flush(): Promise<void>;
|
|
54
|
+
flush(options?: FlushOptions): Promise<void>;
|
|
45
55
|
/**
|
|
46
56
|
* Start periodic flush timer
|
|
47
57
|
*/
|
|
@@ -59,7 +69,7 @@ export declare class AnalyticsCollector {
|
|
|
59
69
|
* Public shutdown method called by main shutdown handler
|
|
60
70
|
* Ensures buffered events are sent before process exits
|
|
61
71
|
*/
|
|
62
|
-
shutdown(): Promise<void>;
|
|
72
|
+
shutdown(options?: FlushOptions): Promise<void>;
|
|
63
73
|
/**
|
|
64
74
|
* Get current buffer size (for testing)
|
|
65
75
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAkB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEpF,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,2DAA2D;AAC3D,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC;CAC9B;AAED;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAG7C,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAK;IAC9C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAiB;IAG1D,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAM;IAGtC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAM;IAC3C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAM;IAC5C,OAAO,CAAC,qBAAqB,CAAgB;IAE7C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAO;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAiB;IAEnD,YAAY,MAAM,EAAE,eAAe,EAAE,IAAI,GAAE,sBAA2B,EAYrE;IAED;;;OAGG;IACU,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,GAAG,OAAO,EAC3B,QAAQ,GAAE,qBAA0B,GACnC,OAAO,CAAC,IAAI,CAAC,CA6Gf;IAED;;;;OAIG;IACU,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2F5D;IAED;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACU,QAAQ,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB/D;IAED;;OAEG;IACI,aAAa,IAAI,MAAM,CAE7B;IAED;;OAEG;IACI,YAAY,IAAI,MAAM,CAE5B;CACF"}
|
|
@@ -17,6 +17,7 @@ export class AnalyticsCollector {
|
|
|
17
17
|
sessionId;
|
|
18
18
|
sequenceNumber = 0;
|
|
19
19
|
isShuttingDown = false;
|
|
20
|
+
sendBatch;
|
|
20
21
|
// Rate limiting state
|
|
21
22
|
consecutiveFailures = 0;
|
|
22
23
|
circuitOpen = false;
|
|
@@ -36,14 +37,15 @@ export class AnalyticsCollector {
|
|
|
36
37
|
recentEventTimestamps = [];
|
|
37
38
|
MAX_BUFFER_SIZE = 100;
|
|
38
39
|
FLUSH_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
39
|
-
constructor(config) {
|
|
40
|
+
constructor(config, deps = {}) {
|
|
40
41
|
this.config = config;
|
|
42
|
+
this.sendBatch = deps.sendBatch ?? sendBatch;
|
|
41
43
|
this.sessionId = this.generateSessionId();
|
|
42
44
|
if (this.config.enabled) {
|
|
43
45
|
this.startFlushTimer();
|
|
44
46
|
logger.debug('Analytics collector initialized', {
|
|
47
|
+
// Never the endpoint: its hostname is operator configuration, and no analytics log carries it.
|
|
45
48
|
level: this.config.level,
|
|
46
|
-
endpoint: this.config.endpoint,
|
|
47
49
|
});
|
|
48
50
|
}
|
|
49
51
|
}
|
|
@@ -152,7 +154,7 @@ export class AnalyticsCollector {
|
|
|
152
154
|
* Called automatically on timer or when buffer is full
|
|
153
155
|
* Implements circuit breaker pattern (3.7)
|
|
154
156
|
*/
|
|
155
|
-
async flush() {
|
|
157
|
+
async flush(options = {}) {
|
|
156
158
|
if (!this.config.enabled || this.buffer.length === 0) {
|
|
157
159
|
return;
|
|
158
160
|
}
|
|
@@ -202,7 +204,9 @@ export class AnalyticsCollector {
|
|
|
202
204
|
logger.debug('Flushing analytics batch', {
|
|
203
205
|
count: eventsToSend.length,
|
|
204
206
|
});
|
|
205
|
-
await sendBatch(eventsToSend, endpoint, this.config.version
|
|
207
|
+
await this.sendBatch(eventsToSend, endpoint, this.config.version, {
|
|
208
|
+
deadlineMs: options.deadlineMs,
|
|
209
|
+
});
|
|
206
210
|
logger.debug('Analytics batch sent successfully', {
|
|
207
211
|
count: eventsToSend.length,
|
|
208
212
|
});
|
|
@@ -211,8 +215,10 @@ export class AnalyticsCollector {
|
|
|
211
215
|
}
|
|
212
216
|
catch (error) {
|
|
213
217
|
this.consecutiveFailures++;
|
|
218
|
+
const failure = error;
|
|
214
219
|
logger.warn('Analytics batch send failed', {
|
|
215
|
-
|
|
220
|
+
name: failure?.name,
|
|
221
|
+
code: failure?.code,
|
|
216
222
|
count: eventsToSend.length,
|
|
217
223
|
consecutiveFailures: this.consecutiveFailures,
|
|
218
224
|
});
|
|
@@ -263,7 +269,7 @@ export class AnalyticsCollector {
|
|
|
263
269
|
* Public shutdown method called by main shutdown handler
|
|
264
270
|
* Ensures buffered events are sent before process exits
|
|
265
271
|
*/
|
|
266
|
-
async shutdown() {
|
|
272
|
+
async shutdown(options = {}) {
|
|
267
273
|
if (this.isShuttingDown) {
|
|
268
274
|
return;
|
|
269
275
|
}
|
|
@@ -274,7 +280,7 @@ export class AnalyticsCollector {
|
|
|
274
280
|
this.stopFlushTimer();
|
|
275
281
|
// Flush remaining events
|
|
276
282
|
if (this.buffer.length > 0) {
|
|
277
|
-
await this.flush();
|
|
283
|
+
await this.flush(options);
|
|
278
284
|
}
|
|
279
285
|
}
|
|
280
286
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"collector.js","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTPS transport layer for analytics events
|
|
3
3
|
* Sends batched events to analytics collection server
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle contract (design plan `plan-analytics-transport-deadline`):
|
|
6
|
+
* - One absolute deadline bounds the whole request — connect, TLS, write, headers and the body
|
|
7
|
+
* drain. Node's per-request idle option is a socket-inactivity timer that every byte resets, so
|
|
8
|
+
* a server trickling its body would never trip it.
|
|
9
|
+
* - The promise settles once, at the response headers: the status line is the batch's fate and
|
|
10
|
+
* nothing reads the body, which is drained to nowhere.
|
|
11
|
+
* - Every way the request can end settles it — headers, a request error, the deadline, or a
|
|
12
|
+
* close with neither.
|
|
4
13
|
*/
|
|
14
|
+
import https from 'https';
|
|
5
15
|
import { AnalyticsEvent } from './types.js';
|
|
16
|
+
/** The absolute deadline for one upload while the server is serving. */
|
|
17
|
+
export declare const REQUEST_DEADLINE_MS = 5000;
|
|
18
|
+
export interface SendBatchOptions {
|
|
19
|
+
/** Absolute wall-clock bound on the whole request: connect, TLS, write, headers, drain. */
|
|
20
|
+
deadlineMs?: number;
|
|
21
|
+
/** `https.request` in production; a fake in tests. */
|
|
22
|
+
request?: typeof https.request;
|
|
23
|
+
}
|
|
6
24
|
/**
|
|
7
25
|
* Send batch of analytics events to collection server
|
|
8
26
|
* Fails silently - analytics should never break the application
|
|
9
27
|
*/
|
|
10
|
-
export declare function sendBatch(events: AnalyticsEvent[], endpoint: string, version: string): Promise<void>;
|
|
28
|
+
export declare function sendBatch(events: AnalyticsEvent[], endpoint: string, version: string, options?: SendBatchOptions): Promise<void>;
|
|
11
29
|
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/analytics/transport.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/analytics/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAC/B,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,cAAc,EAAE,EACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAoHf"}
|
|
@@ -1,19 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTPS transport layer for analytics events
|
|
3
3
|
* Sends batched events to analytics collection server
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle contract (design plan `plan-analytics-transport-deadline`):
|
|
6
|
+
* - One absolute deadline bounds the whole request — connect, TLS, write, headers and the body
|
|
7
|
+
* drain. Node's per-request idle option is a socket-inactivity timer that every byte resets, so
|
|
8
|
+
* a server trickling its body would never trip it.
|
|
9
|
+
* - The promise settles once, at the response headers: the status line is the batch's fate and
|
|
10
|
+
* nothing reads the body, which is drained to nowhere.
|
|
11
|
+
* - Every way the request can end settles it — headers, a request error, the deadline, or a
|
|
12
|
+
* close with neither.
|
|
4
13
|
*/
|
|
5
14
|
import https from 'https';
|
|
6
15
|
import { logger } from '../utils/logger.js';
|
|
16
|
+
/** The absolute deadline for one upload while the server is serving. */
|
|
17
|
+
export const REQUEST_DEADLINE_MS = 5000;
|
|
7
18
|
/**
|
|
8
19
|
* Send batch of analytics events to collection server
|
|
9
20
|
* Fails silently - analytics should never break the application
|
|
10
21
|
*/
|
|
11
|
-
export async function sendBatch(events, endpoint, version) {
|
|
22
|
+
export async function sendBatch(events, endpoint, version, options = {}) {
|
|
12
23
|
if (events.length === 0) {
|
|
13
24
|
return;
|
|
14
25
|
}
|
|
26
|
+
const deadlineMs = options.deadlineMs ?? REQUEST_DEADLINE_MS;
|
|
27
|
+
const request = options.request ?? https.request;
|
|
15
28
|
return new Promise((resolve, reject) => {
|
|
16
29
|
const data = JSON.stringify({ events });
|
|
30
|
+
// Every path settles through here, so a request that fails twice (the deadline, then the
|
|
31
|
+
// socket's own reset) rejects and logs once. The flag is set before any call (G20).
|
|
32
|
+
let settled = false;
|
|
33
|
+
const settle = (fn) => {
|
|
34
|
+
if (settled) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
settled = true;
|
|
38
|
+
fn();
|
|
39
|
+
};
|
|
17
40
|
try {
|
|
18
41
|
const url = new URL(endpoint);
|
|
19
42
|
// SECURITY: Only allow HTTPS for analytics transmission (H-1)
|
|
@@ -23,7 +46,7 @@ export async function sendBatch(events, endpoint, version) {
|
|
|
23
46
|
reject(error);
|
|
24
47
|
return;
|
|
25
48
|
}
|
|
26
|
-
const
|
|
49
|
+
const requestOptions = {
|
|
27
50
|
hostname: url.hostname,
|
|
28
51
|
port: url.port || 443,
|
|
29
52
|
path: url.pathname + url.search,
|
|
@@ -33,17 +56,20 @@ export async function sendBatch(events, endpoint, version) {
|
|
|
33
56
|
'Content-Length': Buffer.byteLength(data),
|
|
34
57
|
'User-Agent': `weather-mcp/${version}`,
|
|
35
58
|
},
|
|
36
|
-
timeout: 5000, // 5 second timeout
|
|
37
59
|
// SECURITY: Explicitly require valid certificates (H-2)
|
|
38
60
|
rejectUnauthorized: true,
|
|
39
61
|
};
|
|
40
|
-
const req =
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
res.on('
|
|
44
|
-
|
|
62
|
+
const req = request(requestOptions, (res) => {
|
|
63
|
+
// Attached so a connection dropped mid-body is handled here rather than relying on Node
|
|
64
|
+
// suppressing the error when nobody listens. The batch has already settled by then.
|
|
65
|
+
res.on('error', (err) => {
|
|
66
|
+
logger.debug('Analytics response error after settle', {
|
|
67
|
+
code: err.code,
|
|
68
|
+
});
|
|
45
69
|
});
|
|
46
|
-
|
|
70
|
+
// Nothing reads the body: drain it to nowhere. The deadline below still bounds the drain.
|
|
71
|
+
res.resume();
|
|
72
|
+
settle(() => {
|
|
47
73
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
48
74
|
logger.debug('Analytics batch sent successfully', {
|
|
49
75
|
count: events.length,
|
|
@@ -56,36 +82,47 @@ export async function sendBatch(events, endpoint, version) {
|
|
|
56
82
|
logger.warn('Analytics batch failed', {
|
|
57
83
|
statusCode: res.statusCode,
|
|
58
84
|
count: events.length,
|
|
59
|
-
error: error.message,
|
|
60
85
|
});
|
|
61
86
|
reject(error);
|
|
62
87
|
}
|
|
63
88
|
});
|
|
64
89
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
// Ref'd on purpose (G114): this timer is what guarantees the request ends, so it must hold
|
|
91
|
+
// the process while the request is live. Cleared on 'close', not on settle, so it also
|
|
92
|
+
// bounds the body drain after the promise has resolved.
|
|
93
|
+
const deadline = setTimeout(() => {
|
|
94
|
+
req.destroy(Object.assign(new Error('Request deadline exceeded'), { code: 'ETIMEDOUT' }));
|
|
95
|
+
}, deadlineMs);
|
|
96
|
+
req.on('close', () => {
|
|
97
|
+
clearTimeout(deadline);
|
|
98
|
+
// A close with neither a response nor an error would otherwise leave the promise pending.
|
|
99
|
+
settle(() => {
|
|
100
|
+
logger.warn('Analytics request closed before a response', { count: events.length });
|
|
101
|
+
reject(new Error('Request closed before a response'));
|
|
69
102
|
});
|
|
70
|
-
reject(err);
|
|
71
103
|
});
|
|
72
|
-
req.on('
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
104
|
+
req.on('error', (err) => {
|
|
105
|
+
// Code only, never the message: a socket error's message embeds the endpoint's hostname
|
|
106
|
+
// (`getaddrinfo ENOTFOUND <host>`).
|
|
107
|
+
settle(() => {
|
|
108
|
+
logger.warn('Analytics request error', {
|
|
109
|
+
code: err.code,
|
|
110
|
+
count: events.length,
|
|
111
|
+
});
|
|
112
|
+
reject(err);
|
|
77
113
|
});
|
|
78
|
-
reject(error);
|
|
79
114
|
});
|
|
80
115
|
req.write(data);
|
|
81
116
|
req.end();
|
|
82
117
|
}
|
|
83
118
|
catch (error) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
119
|
+
settle(() => {
|
|
120
|
+
logger.warn('Analytics transport error', {
|
|
121
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
122
|
+
count: events.length,
|
|
123
|
+
});
|
|
124
|
+
reject(error);
|
|
87
125
|
});
|
|
88
|
-
reject(error);
|
|
89
126
|
}
|
|
90
127
|
});
|
|
91
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/analytics/transport.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/analytics/transport.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,12 @@ import { analytics } from './analytics/index.js';
|
|
|
15
15
|
import { createWeatherServer, SERVER_VERSION } from './server/weatherServer.js';
|
|
16
16
|
import { startLightningPrewarm } from './server/lightningPrewarm.js';
|
|
17
17
|
import { createShutdown, SHUTDOWN_DEADLINE_MS } from './server/shutdown.js';
|
|
18
|
+
/**
|
|
19
|
+
* The shutdown flush's own deadline. It must end before the coordinator's, with room for the
|
|
20
|
+
* steps after it: the MQTT disconnect measured 316 ms with a live broker. Half the budget leaves
|
|
21
|
+
* 750 ms for those steps. A constant, not an env var: garnish is not tuned per install.
|
|
22
|
+
*/
|
|
23
|
+
const ANALYTICS_SHUTDOWN_FLUSH_MS = SHUTDOWN_DEADLINE_MS / 2;
|
|
18
24
|
/**
|
|
19
25
|
* Initialize the LocationStore for managing saved/favorite locations
|
|
20
26
|
* Stores locations in ~/.weather-mcp/locations.json
|
|
@@ -36,8 +42,9 @@ async function main() {
|
|
|
36
42
|
steps: [
|
|
37
43
|
// No new pre-warm subscriptions during teardown.
|
|
38
44
|
{ name: 'lightning-prewarm', run: () => lightningPrewarm?.stop() },
|
|
39
|
-
// Garnish:
|
|
40
|
-
|
|
45
|
+
// Garnish: it flushes under its own deadline, inside the budget, and never reaches the
|
|
46
|
+
// coordinator's — a slow or unreachable analytics endpoint cannot set the exit code.
|
|
47
|
+
{ name: 'analytics', run: () => analytics.shutdown({ deadlineMs: ANALYTICS_SHUTDOWN_FLUSH_MS }) },
|
|
41
48
|
// A no-op when no broker connection exists; never touches the lazy mqtt import.
|
|
42
49
|
{ name: 'mqtt', run: () => blitzortungService.disconnect() },
|
|
43
50
|
// Fires server.onclose synchronously; the memo returns the in-flight run.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG;AAEH,oEAAoE;AACpE,OAAO,eAAe,CAAC;AAEvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAA+B,MAAM,8BAA8B,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5E;;;;GAIG;AACH,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;AAE1C,MAAM,MAAM,GAAG,mBAAmB,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;AAEtD,IAAI,gBAAoD,CAAC;AAEzD;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,6FAA6F;IAC7F,yFAAyF;IACzF,MAAM,QAAQ,GAAG,cAAc,CAAC;QAC9B,UAAU,EAAE,oBAAoB;QAChC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAClC,KAAK,EAAE;YACL,iDAAiD;YACjD,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,gBAAgB,EAAE,IAAI,EAAE,EAAE;YAClE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.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.33.
|
|
3
|
+
"version": "1.33.16",
|
|
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",
|