@jablum/weather-mcp 1.7.0

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 (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1319 -0
  3. package/dist/analytics/anonymizer.d.ts +37 -0
  4. package/dist/analytics/anonymizer.d.ts.map +1 -0
  5. package/dist/analytics/anonymizer.js +112 -0
  6. package/dist/analytics/anonymizer.js.map +1 -0
  7. package/dist/analytics/collector.d.ts +72 -0
  8. package/dist/analytics/collector.d.ts.map +1 -0
  9. package/dist/analytics/collector.js +282 -0
  10. package/dist/analytics/collector.js.map +1 -0
  11. package/dist/analytics/config.d.ts +15 -0
  12. package/dist/analytics/config.d.ts.map +1 -0
  13. package/dist/analytics/config.js +172 -0
  14. package/dist/analytics/config.js.map +1 -0
  15. package/dist/analytics/index.d.ts +8 -0
  16. package/dist/analytics/index.d.ts.map +1 -0
  17. package/dist/analytics/index.js +7 -0
  18. package/dist/analytics/index.js.map +1 -0
  19. package/dist/analytics/middleware.d.ts +33 -0
  20. package/dist/analytics/middleware.d.ts.map +1 -0
  21. package/dist/analytics/middleware.js +99 -0
  22. package/dist/analytics/middleware.js.map +1 -0
  23. package/dist/analytics/transport.d.ts +11 -0
  24. package/dist/analytics/transport.d.ts.map +1 -0
  25. package/dist/analytics/transport.js +92 -0
  26. package/dist/analytics/transport.js.map +1 -0
  27. package/dist/analytics/types.d.ts +74 -0
  28. package/dist/analytics/types.d.ts.map +1 -0
  29. package/dist/analytics/types.js +6 -0
  30. package/dist/analytics/types.js.map +1 -0
  31. package/dist/config/api.d.ts +30 -0
  32. package/dist/config/api.d.ts.map +1 -0
  33. package/dist/config/api.js +32 -0
  34. package/dist/config/api.js.map +1 -0
  35. package/dist/config/cache.d.ts +31 -0
  36. package/dist/config/cache.d.ts.map +1 -0
  37. package/dist/config/cache.js +108 -0
  38. package/dist/config/cache.js.map +1 -0
  39. package/dist/config/displayThresholds.d.ts +83 -0
  40. package/dist/config/displayThresholds.d.ts.map +1 -0
  41. package/dist/config/displayThresholds.js +83 -0
  42. package/dist/config/displayThresholds.js.map +1 -0
  43. package/dist/config/tools.d.ts +44 -0
  44. package/dist/config/tools.d.ts.map +1 -0
  45. package/dist/config/tools.js +269 -0
  46. package/dist/config/tools.js.map +1 -0
  47. package/dist/errors/ApiError.d.ts +62 -0
  48. package/dist/errors/ApiError.d.ts.map +1 -0
  49. package/dist/errors/ApiError.js +171 -0
  50. package/dist/errors/ApiError.js.map +1 -0
  51. package/dist/handlers/airQualityHandler.d.ts +11 -0
  52. package/dist/handlers/airQualityHandler.d.ts.map +1 -0
  53. package/dist/handlers/airQualityHandler.js +154 -0
  54. package/dist/handlers/airQualityHandler.js.map +1 -0
  55. package/dist/handlers/alertsHandler.d.ts +11 -0
  56. package/dist/handlers/alertsHandler.d.ts.map +1 -0
  57. package/dist/handlers/alertsHandler.js +98 -0
  58. package/dist/handlers/alertsHandler.js.map +1 -0
  59. package/dist/handlers/currentConditionsHandler.d.ts +13 -0
  60. package/dist/handlers/currentConditionsHandler.d.ts.map +1 -0
  61. package/dist/handlers/currentConditionsHandler.js +296 -0
  62. package/dist/handlers/currentConditionsHandler.js.map +1 -0
  63. package/dist/handlers/forecastHandler.d.ts +16 -0
  64. package/dist/handlers/forecastHandler.d.ts.map +1 -0
  65. package/dist/handlers/forecastHandler.js +454 -0
  66. package/dist/handlers/forecastHandler.js.map +1 -0
  67. package/dist/handlers/historicalWeatherHandler.d.ts +12 -0
  68. package/dist/handlers/historicalWeatherHandler.d.ts.map +1 -0
  69. package/dist/handlers/historicalWeatherHandler.js +188 -0
  70. package/dist/handlers/historicalWeatherHandler.js.map +1 -0
  71. package/dist/handlers/lightningHandler.d.ts +14 -0
  72. package/dist/handlers/lightningHandler.d.ts.map +1 -0
  73. package/dist/handlers/lightningHandler.js +258 -0
  74. package/dist/handlers/lightningHandler.js.map +1 -0
  75. package/dist/handlers/locationHandler.d.ts +12 -0
  76. package/dist/handlers/locationHandler.d.ts.map +1 -0
  77. package/dist/handlers/locationHandler.js +149 -0
  78. package/dist/handlers/locationHandler.js.map +1 -0
  79. package/dist/handlers/marineConditionsHandler.d.ts +13 -0
  80. package/dist/handlers/marineConditionsHandler.d.ts.map +1 -0
  81. package/dist/handlers/marineConditionsHandler.js +270 -0
  82. package/dist/handlers/marineConditionsHandler.js.map +1 -0
  83. package/dist/handlers/riverConditionsHandler.d.ts +11 -0
  84. package/dist/handlers/riverConditionsHandler.d.ts.map +1 -0
  85. package/dist/handlers/riverConditionsHandler.js +176 -0
  86. package/dist/handlers/riverConditionsHandler.js.map +1 -0
  87. package/dist/handlers/savedLocationsHandler.d.ts +50 -0
  88. package/dist/handlers/savedLocationsHandler.d.ts.map +1 -0
  89. package/dist/handlers/savedLocationsHandler.js +397 -0
  90. package/dist/handlers/savedLocationsHandler.js.map +1 -0
  91. package/dist/handlers/statusHandler.d.ts +12 -0
  92. package/dist/handlers/statusHandler.d.ts.map +1 -0
  93. package/dist/handlers/statusHandler.js +115 -0
  94. package/dist/handlers/statusHandler.js.map +1 -0
  95. package/dist/handlers/weatherImageryHandler.d.ts +14 -0
  96. package/dist/handlers/weatherImageryHandler.d.ts.map +1 -0
  97. package/dist/handlers/weatherImageryHandler.js +143 -0
  98. package/dist/handlers/weatherImageryHandler.js.map +1 -0
  99. package/dist/handlers/wildfireHandler.d.ts +11 -0
  100. package/dist/handlers/wildfireHandler.d.ts.map +1 -0
  101. package/dist/handlers/wildfireHandler.js +186 -0
  102. package/dist/handlers/wildfireHandler.js.map +1 -0
  103. package/dist/index.d.ts +7 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +735 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/services/blitzortung.d.ts +67 -0
  108. package/dist/services/blitzortung.d.ts.map +1 -0
  109. package/dist/services/blitzortung.js +475 -0
  110. package/dist/services/blitzortung.js.map +1 -0
  111. package/dist/services/geocoding.d.ts +57 -0
  112. package/dist/services/geocoding.d.ts.map +1 -0
  113. package/dist/services/geocoding.js +393 -0
  114. package/dist/services/geocoding.js.map +1 -0
  115. package/dist/services/locationStore.d.ts +62 -0
  116. package/dist/services/locationStore.d.ts.map +1 -0
  117. package/dist/services/locationStore.js +201 -0
  118. package/dist/services/locationStore.js.map +1 -0
  119. package/dist/services/ncei.d.ts +61 -0
  120. package/dist/services/ncei.d.ts.map +1 -0
  121. package/dist/services/ncei.js +126 -0
  122. package/dist/services/ncei.js.map +1 -0
  123. package/dist/services/nifc.d.ts +44 -0
  124. package/dist/services/nifc.d.ts.map +1 -0
  125. package/dist/services/nifc.js +159 -0
  126. package/dist/services/nifc.js.map +1 -0
  127. package/dist/services/noaa.d.ts +161 -0
  128. package/dist/services/noaa.d.ts.map +1 -0
  129. package/dist/services/noaa.js +681 -0
  130. package/dist/services/noaa.js.map +1 -0
  131. package/dist/services/nominatim.d.ts +62 -0
  132. package/dist/services/nominatim.d.ts.map +1 -0
  133. package/dist/services/nominatim.js +254 -0
  134. package/dist/services/nominatim.js.map +1 -0
  135. package/dist/services/openmeteo.d.ts +189 -0
  136. package/dist/services/openmeteo.d.ts.map +1 -0
  137. package/dist/services/openmeteo.js +936 -0
  138. package/dist/services/openmeteo.js.map +1 -0
  139. package/dist/services/rainviewer.d.ts +37 -0
  140. package/dist/services/rainviewer.d.ts.map +1 -0
  141. package/dist/services/rainviewer.js +115 -0
  142. package/dist/services/rainviewer.js.map +1 -0
  143. package/dist/types/imagery.d.ts +82 -0
  144. package/dist/types/imagery.d.ts.map +1 -0
  145. package/dist/types/imagery.js +6 -0
  146. package/dist/types/imagery.js.map +1 -0
  147. package/dist/types/lightning.d.ts +89 -0
  148. package/dist/types/lightning.d.ts.map +1 -0
  149. package/dist/types/lightning.js +6 -0
  150. package/dist/types/lightning.js.map +1 -0
  151. package/dist/types/noaa.d.ts +535 -0
  152. package/dist/types/noaa.d.ts.map +1 -0
  153. package/dist/types/noaa.js +5 -0
  154. package/dist/types/noaa.js.map +1 -0
  155. package/dist/types/nominatim.d.ts +72 -0
  156. package/dist/types/nominatim.d.ts.map +1 -0
  157. package/dist/types/nominatim.js +6 -0
  158. package/dist/types/nominatim.js.map +1 -0
  159. package/dist/types/openmeteo.d.ts +583 -0
  160. package/dist/types/openmeteo.d.ts.map +1 -0
  161. package/dist/types/openmeteo.js +6 -0
  162. package/dist/types/openmeteo.js.map +1 -0
  163. package/dist/types/savedLocations.d.ts +58 -0
  164. package/dist/types/savedLocations.d.ts.map +1 -0
  165. package/dist/types/savedLocations.js +5 -0
  166. package/dist/types/savedLocations.js.map +1 -0
  167. package/dist/types/wildfire.d.ts +83 -0
  168. package/dist/types/wildfire.d.ts.map +1 -0
  169. package/dist/types/wildfire.js +5 -0
  170. package/dist/types/wildfire.js.map +1 -0
  171. package/dist/utils/airQuality.d.ts +54 -0
  172. package/dist/utils/airQuality.d.ts.map +1 -0
  173. package/dist/utils/airQuality.js +251 -0
  174. package/dist/utils/airQuality.js.map +1 -0
  175. package/dist/utils/cache.d.ts +69 -0
  176. package/dist/utils/cache.d.ts.map +1 -0
  177. package/dist/utils/cache.js +164 -0
  178. package/dist/utils/cache.js.map +1 -0
  179. package/dist/utils/distance.d.ts +25 -0
  180. package/dist/utils/distance.d.ts.map +1 -0
  181. package/dist/utils/distance.js +40 -0
  182. package/dist/utils/distance.js.map +1 -0
  183. package/dist/utils/fireWeather.d.ts +76 -0
  184. package/dist/utils/fireWeather.d.ts.map +1 -0
  185. package/dist/utils/fireWeather.js +243 -0
  186. package/dist/utils/fireWeather.js.map +1 -0
  187. package/dist/utils/geography.d.ts +79 -0
  188. package/dist/utils/geography.d.ts.map +1 -0
  189. package/dist/utils/geography.js +266 -0
  190. package/dist/utils/geography.js.map +1 -0
  191. package/dist/utils/geohash.d.ts +62 -0
  192. package/dist/utils/geohash.d.ts.map +1 -0
  193. package/dist/utils/geohash.js +146 -0
  194. package/dist/utils/geohash.js.map +1 -0
  195. package/dist/utils/locationResolver.d.ts +34 -0
  196. package/dist/utils/locationResolver.d.ts.map +1 -0
  197. package/dist/utils/locationResolver.js +120 -0
  198. package/dist/utils/locationResolver.js.map +1 -0
  199. package/dist/utils/logger.d.ts +75 -0
  200. package/dist/utils/logger.d.ts.map +1 -0
  201. package/dist/utils/logger.js +153 -0
  202. package/dist/utils/logger.js.map +1 -0
  203. package/dist/utils/marine.d.ts +59 -0
  204. package/dist/utils/marine.d.ts.map +1 -0
  205. package/dist/utils/marine.js +215 -0
  206. package/dist/utils/marine.js.map +1 -0
  207. package/dist/utils/normals.d.ts +86 -0
  208. package/dist/utils/normals.d.ts.map +1 -0
  209. package/dist/utils/normals.js +223 -0
  210. package/dist/utils/normals.js.map +1 -0
  211. package/dist/utils/snow.d.ts +45 -0
  212. package/dist/utils/snow.d.ts.map +1 -0
  213. package/dist/utils/snow.js +144 -0
  214. package/dist/utils/snow.js.map +1 -0
  215. package/dist/utils/temperatureConversion.d.ts +12 -0
  216. package/dist/utils/temperatureConversion.d.ts.map +1 -0
  217. package/dist/utils/temperatureConversion.js +17 -0
  218. package/dist/utils/temperatureConversion.js.map +1 -0
  219. package/dist/utils/timezone.d.ts +56 -0
  220. package/dist/utils/timezone.d.ts.map +1 -0
  221. package/dist/utils/timezone.js +167 -0
  222. package/dist/utils/timezone.js.map +1 -0
  223. package/dist/utils/units.d.ts +69 -0
  224. package/dist/utils/units.d.ts.map +1 -0
  225. package/dist/utils/units.js +158 -0
  226. package/dist/utils/units.js.map +1 -0
  227. package/dist/utils/validation.d.ts +89 -0
  228. package/dist/utils/validation.d.ts.map +1 -0
  229. package/dist/utils/validation.js +177 -0
  230. package/dist/utils/validation.js.map +1 -0
  231. package/dist/utils/version.d.ts +15 -0
  232. package/dist/utils/version.d.ts.map +1 -0
  233. package/dist/utils/version.js +24 -0
  234. package/dist/utils/version.js.map +1 -0
  235. package/package.json +74 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Analytics configuration and singleton collector instance
3
+ * Loads settings from environment variables with secure defaults
4
+ */
5
+ import crypto from 'crypto';
6
+ import { readFileSync } from 'fs';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import os from 'os';
10
+ import { fileURLToPath } from 'url';
11
+ import { dirname, join } from 'path';
12
+ import { logger } from '../utils/logger.js';
13
+ import { AnalyticsCollector } from './collector.js';
14
+ // Read version from package.json to ensure single source of truth
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
18
+ /**
19
+ * Default analytics endpoint (production analytics server)
20
+ */
21
+ const DEFAULT_ENDPOINT = 'https://analytics.weather-mcp.com/v1/events';
22
+ /**
23
+ * Validate analytics endpoint for security
24
+ * Prevents SSRF attacks and enforces HTTPS
25
+ */
26
+ function validateAnalyticsEndpoint(endpoint) {
27
+ let url;
28
+ try {
29
+ url = new URL(endpoint);
30
+ }
31
+ catch (error) {
32
+ throw new Error('Invalid ANALYTICS_ENDPOINT: must be a valid URL');
33
+ }
34
+ // SECURITY: Only allow HTTPS
35
+ if (url.protocol !== 'https:') {
36
+ throw new Error('Invalid ANALYTICS_ENDPOINT: must use HTTPS protocol');
37
+ }
38
+ // SECURITY: Prevent SSRF to internal networks
39
+ const hostname = url.hostname.toLowerCase();
40
+ if (hostname === 'localhost' ||
41
+ hostname === '127.0.0.1' ||
42
+ hostname === '::1' ||
43
+ hostname.startsWith('10.') ||
44
+ hostname.startsWith('172.16.') ||
45
+ hostname.startsWith('172.17.') ||
46
+ hostname.startsWith('172.18.') ||
47
+ hostname.startsWith('172.19.') ||
48
+ hostname.startsWith('172.20.') ||
49
+ hostname.startsWith('172.21.') ||
50
+ hostname.startsWith('172.22.') ||
51
+ hostname.startsWith('172.23.') ||
52
+ hostname.startsWith('172.24.') ||
53
+ hostname.startsWith('172.25.') ||
54
+ hostname.startsWith('172.26.') ||
55
+ hostname.startsWith('172.27.') ||
56
+ hostname.startsWith('172.28.') ||
57
+ hostname.startsWith('172.29.') ||
58
+ hostname.startsWith('172.30.') ||
59
+ hostname.startsWith('172.31.') ||
60
+ hostname.startsWith('192.168.') ||
61
+ hostname.startsWith('169.254.') || // Link-local
62
+ hostname.endsWith('.local')) {
63
+ throw new Error('Invalid ANALYTICS_ENDPOINT: cannot point to internal network');
64
+ }
65
+ // SECURITY: Require domain name (not IP address)
66
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
67
+ throw new Error('Invalid ANALYTICS_ENDPOINT: IP addresses not allowed, use domain name');
68
+ }
69
+ // SECURITY: Validate port range
70
+ const port = url.port ? parseInt(url.port) : 443;
71
+ if (port < 1 || port > 65535 || (port !== 443 && port < 1024)) {
72
+ throw new Error('Invalid ANALYTICS_ENDPOINT: invalid port number');
73
+ }
74
+ }
75
+ /**
76
+ * Get or generate analytics salt for session ID hashing
77
+ * Generates a unique salt per installation and persists it
78
+ */
79
+ function getOrGenerateAnalyticsSalt() {
80
+ // Check environment variable first
81
+ if (process.env.ANALYTICS_SALT) {
82
+ return process.env.ANALYTICS_SALT;
83
+ }
84
+ // Store in user's config directory (NOT in project directory)
85
+ const configDir = path.join(os.homedir(), '.weather-mcp');
86
+ const saltFile = path.join(configDir, 'analytics-salt');
87
+ try {
88
+ if (fs.existsSync(saltFile)) {
89
+ return fs.readFileSync(saltFile, 'utf8').trim();
90
+ }
91
+ }
92
+ catch (err) {
93
+ logger.warn('Could not read analytics salt file', {
94
+ error: err instanceof Error ? err.message : 'Unknown error',
95
+ });
96
+ }
97
+ // Generate new random salt
98
+ const newSalt = crypto.randomBytes(32).toString('hex');
99
+ try {
100
+ fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
101
+ fs.writeFileSync(saltFile, newSalt, { mode: 0o600 });
102
+ logger.info('Generated new analytics salt');
103
+ }
104
+ catch (err) {
105
+ logger.warn('Could not persist analytics salt', {
106
+ error: err instanceof Error ? err.message : 'Unknown error',
107
+ });
108
+ // Continue with in-memory salt (regenerates each restart)
109
+ }
110
+ return newSalt;
111
+ }
112
+ /**
113
+ * Load and validate analytics configuration from environment variables
114
+ */
115
+ function loadAnalyticsConfig() {
116
+ // Analytics disabled by default (users must opt-in)
117
+ const enabled = process.env.ANALYTICS_ENABLED === 'true';
118
+ // Analytics level: minimal (default), standard, detailed
119
+ let level = 'minimal';
120
+ const levelEnv = process.env.ANALYTICS_LEVEL?.toLowerCase();
121
+ if (levelEnv === 'standard' || levelEnv === 'detailed') {
122
+ level = levelEnv;
123
+ }
124
+ else if (levelEnv && levelEnv !== 'minimal') {
125
+ logger.warn('Invalid ANALYTICS_LEVEL, using minimal', {
126
+ provided: levelEnv,
127
+ securityEvent: true,
128
+ });
129
+ }
130
+ // Analytics endpoint (custom server or default)
131
+ const endpoint = process.env.ANALYTICS_ENDPOINT || DEFAULT_ENDPOINT;
132
+ // Validate endpoint for security
133
+ try {
134
+ validateAnalyticsEndpoint(endpoint);
135
+ }
136
+ catch (error) {
137
+ const errorMsg = error instanceof Error ? error.message : 'Unknown error';
138
+ logger.error(`Invalid ANALYTICS_ENDPOINT configuration: ${errorMsg}`, error instanceof Error ? error : new Error(String(error)));
139
+ // Disable analytics if endpoint is invalid (fail-safe)
140
+ return {
141
+ enabled: false,
142
+ level: 'minimal',
143
+ endpoint: DEFAULT_ENDPOINT,
144
+ version: packageJson.version,
145
+ };
146
+ }
147
+ // Salt for session ID hashing (auto-generated if not provided)
148
+ const salt = getOrGenerateAnalyticsSalt();
149
+ const config = {
150
+ enabled,
151
+ level,
152
+ endpoint,
153
+ version: packageJson.version,
154
+ salt,
155
+ };
156
+ if (enabled) {
157
+ logger.info('Analytics configuration loaded', {
158
+ level,
159
+ endpoint: endpoint === DEFAULT_ENDPOINT ? 'default' : 'custom',
160
+ });
161
+ }
162
+ else {
163
+ logger.info('Analytics disabled by user preference');
164
+ }
165
+ return config;
166
+ }
167
+ /**
168
+ * Singleton analytics collector instance
169
+ * Exported for use throughout the application
170
+ */
171
+ export const analytics = new AnalyticsCollector(loadAnalyticsConfig());
172
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/analytics/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Analytics module - Privacy-first usage tracking
3
+ * Implements anonymous, opt-out analytics as defined in docs/ANALYTICS_MCP_PLAN.md
4
+ */
5
+ export { analytics } from './config.js';
6
+ export { withAnalytics, createMetadataExtractor } from './middleware.js';
7
+ export type { AnalyticsLevel, ToolExecutionMetadata } from './types.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACzE,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Analytics module - Privacy-first usage tracking
3
+ * Implements anonymous, opt-out analytics as defined in docs/ANALYTICS_MCP_PLAN.md
4
+ */
5
+ export { analytics } from './config.js';
6
+ export { withAnalytics, createMetadataExtractor } from './middleware.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Analytics middleware for tool handlers
3
+ * Automatically tracks tool executions with performance metrics
4
+ */
5
+ import { ToolExecutionMetadata } from './types.js';
6
+ /**
7
+ * Wrapper function that adds analytics tracking to tool handlers
8
+ * Captures execution time, errors, and custom metadata
9
+ *
10
+ * @param toolName - Name of the MCP tool being executed
11
+ * @param handler - The tool handler function to wrap
12
+ * @param metadataExtractor - Optional function to extract metadata from handler result
13
+ * @returns Wrapped handler with analytics tracking
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * export async function getForecastHandler(args: ForecastArgs) {
18
+ * return withAnalytics('get_forecast', async () => {
19
+ * // ... handler implementation
20
+ * return result;
21
+ * }, (result) => ({
22
+ * service: result.source,
23
+ * cache_hit: result.cached,
24
+ * }));
25
+ * }
26
+ * ```
27
+ */
28
+ export declare function withAnalytics<T>(toolName: string, handler: () => Promise<T>, metadataExtractor?: (result: T) => Partial<ToolExecutionMetadata>): Promise<T>;
29
+ /**
30
+ * Helper to create metadata extractor for common patterns
31
+ */
32
+ export declare function createMetadataExtractor<T>(extractor: (result: T) => Partial<ToolExecutionMetadata>): (result: T) => Partial<ToolExecutionMetadata>;
33
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/analytics/middleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,qBAAqB,CAAC,GAChE,OAAO,CAAC,CAAC,CAAC,CAgEZ;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,qBAAqB,CAAC,GACvD,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAE/C"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Analytics middleware for tool handlers
3
+ * Automatically tracks tool executions with performance metrics
4
+ */
5
+ import { logger } from '../utils/logger.js';
6
+ import { analytics } from './config.js';
7
+ /**
8
+ * Wrapper function that adds analytics tracking to tool handlers
9
+ * Captures execution time, errors, and custom metadata
10
+ *
11
+ * @param toolName - Name of the MCP tool being executed
12
+ * @param handler - The tool handler function to wrap
13
+ * @param metadataExtractor - Optional function to extract metadata from handler result
14
+ * @returns Wrapped handler with analytics tracking
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * export async function getForecastHandler(args: ForecastArgs) {
19
+ * return withAnalytics('get_forecast', async () => {
20
+ * // ... handler implementation
21
+ * return result;
22
+ * }, (result) => ({
23
+ * service: result.source,
24
+ * cache_hit: result.cached,
25
+ * }));
26
+ * }
27
+ * ```
28
+ */
29
+ export async function withAnalytics(toolName, handler, metadataExtractor) {
30
+ const startTime = Date.now();
31
+ let metadata = {};
32
+ try {
33
+ // Execute the handler
34
+ const result = await handler();
35
+ // Calculate response time
36
+ const responseTimeMs = Date.now() - startTime;
37
+ metadata.response_time_ms = responseTimeMs;
38
+ // Extract additional metadata from result if extractor provided
39
+ if (metadataExtractor) {
40
+ try {
41
+ const extracted = metadataExtractor(result);
42
+ metadata = { ...metadata, ...extracted };
43
+ }
44
+ catch (error) {
45
+ logger.warn('Analytics metadata extraction error', {
46
+ tool: toolName,
47
+ error: error instanceof Error ? error.message : 'Unknown error',
48
+ });
49
+ }
50
+ }
51
+ // Track successful execution
52
+ await analytics.trackToolCall(toolName, 'success', metadata);
53
+ return result;
54
+ }
55
+ catch (error) {
56
+ // Calculate response time even for errors
57
+ const responseTimeMs = Date.now() - startTime;
58
+ metadata.response_time_ms = responseTimeMs;
59
+ // Categorize error type
60
+ let errorType = 'unknown';
61
+ if (error instanceof Error) {
62
+ const errorName = error.constructor.name;
63
+ // Map error classes to analytics categories
64
+ if (errorName.includes('Validation') || errorName.includes('Invalid')) {
65
+ errorType = 'validation';
66
+ }
67
+ else if (errorName.includes('NotFound') || errorName.includes('404')) {
68
+ errorType = 'not_found';
69
+ }
70
+ else if (errorName.includes('RateLimit')) {
71
+ errorType = 'rate_limit';
72
+ }
73
+ else if (errorName.includes('Timeout')) {
74
+ errorType = 'timeout';
75
+ }
76
+ else if (errorName.includes('Network') || errorName.includes('Connection')) {
77
+ errorType = 'network';
78
+ }
79
+ else if (errorName.includes('Service') || errorName.includes('API')) {
80
+ errorType = 'service_error';
81
+ }
82
+ else {
83
+ errorType = errorName.toLowerCase().replace('error', '').trim() || 'unknown';
84
+ }
85
+ }
86
+ metadata.error_type = errorType;
87
+ // Track error execution
88
+ await analytics.trackToolCall(toolName, 'error', metadata);
89
+ // Re-throw the error to maintain normal error handling flow
90
+ throw error;
91
+ }
92
+ }
93
+ /**
94
+ * Helper to create metadata extractor for common patterns
95
+ */
96
+ export function createMetadataExtractor(extractor) {
97
+ return extractor;
98
+ }
99
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/analytics/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * HTTPS transport layer for analytics events
3
+ * Sends batched events to analytics collection server
4
+ */
5
+ import { AnalyticsEvent } from './types.js';
6
+ /**
7
+ * Send batch of analytics events to collection server
8
+ * Fails silently - analytics should never break the application
9
+ */
10
+ export declare function sendBatch(events: AnalyticsEvent[], endpoint: string, version: string): Promise<void>;
11
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/analytics/transport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,cAAc,EAAE,EACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAwFf"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * HTTPS transport layer for analytics events
3
+ * Sends batched events to analytics collection server
4
+ */
5
+ import https from 'https';
6
+ import { logger } from '../utils/logger.js';
7
+ /**
8
+ * Send batch of analytics events to collection server
9
+ * Fails silently - analytics should never break the application
10
+ */
11
+ export async function sendBatch(events, endpoint, version) {
12
+ if (events.length === 0) {
13
+ return;
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ const data = JSON.stringify({ events });
17
+ try {
18
+ const url = new URL(endpoint);
19
+ // SECURITY: Only allow HTTPS for analytics transmission (H-1)
20
+ if (url.protocol !== 'https:') {
21
+ const error = new Error(`Analytics endpoint must use HTTPS for secure transmission (got ${url.protocol})`);
22
+ logger.error('Analytics endpoint must use HTTPS', error);
23
+ reject(error);
24
+ return;
25
+ }
26
+ const options = {
27
+ hostname: url.hostname,
28
+ port: url.port || 443,
29
+ path: url.pathname + url.search,
30
+ method: 'POST',
31
+ headers: {
32
+ 'Content-Type': 'application/json',
33
+ 'Content-Length': Buffer.byteLength(data),
34
+ 'User-Agent': `weather-mcp/${version}`,
35
+ },
36
+ timeout: 5000, // 5 second timeout
37
+ // SECURITY: Explicitly require valid certificates (H-2)
38
+ rejectUnauthorized: true,
39
+ };
40
+ const req = https.request(options, (res) => {
41
+ let responseData = '';
42
+ // Consume response data
43
+ res.on('data', (chunk) => {
44
+ responseData += chunk;
45
+ });
46
+ res.on('end', () => {
47
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
48
+ logger.debug('Analytics batch sent successfully', {
49
+ count: events.length,
50
+ statusCode: res.statusCode,
51
+ });
52
+ resolve();
53
+ }
54
+ else {
55
+ const error = new Error(`HTTP ${res.statusCode}`);
56
+ logger.warn('Analytics batch failed', {
57
+ statusCode: res.statusCode,
58
+ count: events.length,
59
+ error: error.message,
60
+ });
61
+ reject(error);
62
+ }
63
+ });
64
+ });
65
+ req.on('error', (err) => {
66
+ logger.warn('Analytics request error', {
67
+ error: err.message,
68
+ count: events.length,
69
+ });
70
+ reject(err);
71
+ });
72
+ req.on('timeout', () => {
73
+ req.destroy();
74
+ const error = new Error('Request timeout');
75
+ logger.warn('Analytics request timeout', {
76
+ count: events.length,
77
+ });
78
+ reject(error);
79
+ });
80
+ req.write(data);
81
+ req.end();
82
+ }
83
+ catch (error) {
84
+ logger.warn('Analytics transport error', {
85
+ error: error instanceof Error ? error.message : 'Unknown error',
86
+ count: events.length,
87
+ });
88
+ reject(error);
89
+ }
90
+ });
91
+ }
92
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/analytics/transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Analytics type definitions for Weather MCP Server
3
+ * Implements privacy-first analytics as defined in docs/ANALYTICS_MCP_PLAN.md
4
+ */
5
+ export type AnalyticsLevel = 'minimal' | 'standard' | 'detailed';
6
+ export type EventStatus = 'success' | 'error';
7
+ /**
8
+ * Base analytics event (minimal level)
9
+ */
10
+ export interface BaseAnalyticsEvent {
11
+ version: string;
12
+ tool: string;
13
+ status: EventStatus;
14
+ timestamp_hour: string;
15
+ analytics_level: AnalyticsLevel;
16
+ error_type?: string;
17
+ }
18
+ /**
19
+ * Standard level analytics event
20
+ * Includes performance and service metrics
21
+ */
22
+ export interface StandardAnalyticsEvent extends BaseAnalyticsEvent {
23
+ analytics_level: 'standard' | 'detailed';
24
+ response_time_ms?: number;
25
+ service?: 'noaa' | 'openmeteo' | 'nifc' | 'usgs' | 'blitzortung' | 'rainviewer';
26
+ cache_hit?: boolean;
27
+ retry_count?: number;
28
+ country?: string;
29
+ }
30
+ /**
31
+ * Detailed level analytics event
32
+ * Includes anonymized workflow patterns
33
+ */
34
+ export interface DetailedAnalyticsEvent extends StandardAnalyticsEvent {
35
+ analytics_level: 'detailed';
36
+ parameters?: Record<string, unknown>;
37
+ session_id?: string;
38
+ sequence_number?: number;
39
+ }
40
+ /**
41
+ * Union type for all analytics events
42
+ */
43
+ export type AnalyticsEvent = BaseAnalyticsEvent | StandardAnalyticsEvent | DetailedAnalyticsEvent;
44
+ /**
45
+ * Analytics configuration
46
+ */
47
+ export interface AnalyticsConfig {
48
+ enabled: boolean;
49
+ level: AnalyticsLevel;
50
+ endpoint: string;
51
+ version: string;
52
+ salt?: string;
53
+ }
54
+ /**
55
+ * Event batch for transport
56
+ */
57
+ export interface EventBatch {
58
+ events: AnalyticsEvent[];
59
+ }
60
+ /**
61
+ * Metadata collected during tool execution
62
+ */
63
+ export interface ToolExecutionMetadata {
64
+ response_time_ms?: number;
65
+ service?: string;
66
+ cache_hit?: boolean;
67
+ retry_count?: number;
68
+ country?: string;
69
+ parameters?: Record<string, unknown>;
70
+ error_type?: string;
71
+ session_id?: string;
72
+ sequence_number?: number;
73
+ }
74
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analytics/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;AACjE,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,cAAc,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,kBAAkB;IAChE,eAAe,EAAE,UAAU,GAAG,UAAU,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC;IAChF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAuB,SAAQ,sBAAsB;IACpE,eAAe,EAAE,UAAU,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,sBAAsB,GACtB,sBAAsB,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Analytics type definitions for Weather MCP Server
3
+ * Implements privacy-first analytics as defined in docs/ANALYTICS_MCP_PLAN.md
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/analytics/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * API configuration for external weather services
3
+ *
4
+ * Most APIs used by this server are free and require no authentication.
5
+ * Optional API tokens can be configured for enhanced features.
6
+ */
7
+ /**
8
+ * NCEI (National Centers for Environmental Information) API token
9
+ *
10
+ * OPTIONAL: Get a free token at https://www.ncdc.noaa.gov/cdo-web/token
11
+ *
12
+ * Benefits of providing a token:
13
+ * - Access to official NOAA climate normals for US locations
14
+ * - More accurate than computed normals from reanalysis data
15
+ *
16
+ * If not provided:
17
+ * - Climate normals will be computed from Open-Meteo historical data
18
+ * - Works globally (not just US)
19
+ * - No setup required
20
+ *
21
+ * Rate limits with token:
22
+ * - 5 requests per second
23
+ * - 10,000 requests per day
24
+ */
25
+ export declare const NCEI_API_TOKEN: string | undefined;
26
+ /**
27
+ * Check if NCEI API is available (token configured)
28
+ */
29
+ export declare function isNCEIAvailable(): boolean;
30
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/config/api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,oBAA6B,CAAC;AAEzD;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * API configuration for external weather services
3
+ *
4
+ * Most APIs used by this server are free and require no authentication.
5
+ * Optional API tokens can be configured for enhanced features.
6
+ */
7
+ /**
8
+ * NCEI (National Centers for Environmental Information) API token
9
+ *
10
+ * OPTIONAL: Get a free token at https://www.ncdc.noaa.gov/cdo-web/token
11
+ *
12
+ * Benefits of providing a token:
13
+ * - Access to official NOAA climate normals for US locations
14
+ * - More accurate than computed normals from reanalysis data
15
+ *
16
+ * If not provided:
17
+ * - Climate normals will be computed from Open-Meteo historical data
18
+ * - Works globally (not just US)
19
+ * - No setup required
20
+ *
21
+ * Rate limits with token:
22
+ * - 5 requests per second
23
+ * - 10,000 requests per day
24
+ */
25
+ export const NCEI_API_TOKEN = process.env.NCEI_API_TOKEN;
26
+ /**
27
+ * Check if NCEI API is available (token configured)
28
+ */
29
+ export function isNCEIAvailable() {
30
+ return !!NCEI_API_TOKEN && NCEI_API_TOKEN.trim().length > 0;
31
+ }
32
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/config/api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,CAAC,cAAc,IAAI,cAAc,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC9D,CAAC"}