@dangahagan/weather-mcp 1.6.1 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +249 -30
  2. package/dist/analytics/anonymizer.d.ts +37 -0
  3. package/dist/analytics/anonymizer.d.ts.map +1 -0
  4. package/dist/analytics/anonymizer.js +112 -0
  5. package/dist/analytics/anonymizer.js.map +1 -0
  6. package/dist/analytics/collector.d.ts +72 -0
  7. package/dist/analytics/collector.d.ts.map +1 -0
  8. package/dist/analytics/collector.js +282 -0
  9. package/dist/analytics/collector.js.map +1 -0
  10. package/dist/analytics/config.d.ts +15 -0
  11. package/dist/analytics/config.d.ts.map +1 -0
  12. package/dist/analytics/config.js +172 -0
  13. package/dist/analytics/config.js.map +1 -0
  14. package/dist/analytics/index.d.ts +8 -0
  15. package/dist/analytics/index.d.ts.map +1 -0
  16. package/dist/analytics/index.js +7 -0
  17. package/dist/analytics/index.js.map +1 -0
  18. package/dist/analytics/middleware.d.ts +33 -0
  19. package/dist/analytics/middleware.d.ts.map +1 -0
  20. package/dist/analytics/middleware.js +99 -0
  21. package/dist/analytics/middleware.js.map +1 -0
  22. package/dist/analytics/transport.d.ts +11 -0
  23. package/dist/analytics/transport.d.ts.map +1 -0
  24. package/dist/analytics/transport.js +92 -0
  25. package/dist/analytics/transport.js.map +1 -0
  26. package/dist/analytics/types.d.ts +74 -0
  27. package/dist/analytics/types.d.ts.map +1 -0
  28. package/dist/analytics/types.js +6 -0
  29. package/dist/analytics/types.js.map +1 -0
  30. package/dist/config/tools.d.ts +1 -1
  31. package/dist/config/tools.d.ts.map +1 -1
  32. package/dist/config/tools.js +25 -5
  33. package/dist/config/tools.js.map +1 -1
  34. package/dist/errors/ApiError.d.ts +6 -6
  35. package/dist/errors/ApiError.d.ts.map +1 -1
  36. package/dist/errors/ApiError.js.map +1 -1
  37. package/dist/handlers/forecastHandler.d.ts +2 -1
  38. package/dist/handlers/forecastHandler.d.ts.map +1 -1
  39. package/dist/handlers/forecastHandler.js +5 -4
  40. package/dist/handlers/forecastHandler.js.map +1 -1
  41. package/dist/handlers/locationHandler.d.ts +3 -2
  42. package/dist/handlers/locationHandler.d.ts.map +1 -1
  43. package/dist/handlers/locationHandler.js +27 -17
  44. package/dist/handlers/locationHandler.js.map +1 -1
  45. package/dist/handlers/riverConditionsHandler.js +13 -9
  46. package/dist/handlers/riverConditionsHandler.js.map +1 -1
  47. package/dist/handlers/savedLocationsHandler.d.ts +50 -0
  48. package/dist/handlers/savedLocationsHandler.d.ts.map +1 -0
  49. package/dist/handlers/savedLocationsHandler.js +399 -0
  50. package/dist/handlers/savedLocationsHandler.js.map +1 -0
  51. package/dist/handlers/statusHandler.js +2 -2
  52. package/dist/handlers/statusHandler.js.map +1 -1
  53. package/dist/index.js +210 -46
  54. package/dist/index.js.map +1 -1
  55. package/dist/services/geocoding.d.ts +57 -0
  56. package/dist/services/geocoding.d.ts.map +1 -0
  57. package/dist/services/geocoding.js +393 -0
  58. package/dist/services/geocoding.js.map +1 -0
  59. package/dist/services/locationStore.d.ts +62 -0
  60. package/dist/services/locationStore.d.ts.map +1 -0
  61. package/dist/services/locationStore.js +201 -0
  62. package/dist/services/locationStore.js.map +1 -0
  63. package/dist/services/nifc.d.ts.map +1 -1
  64. package/dist/services/nifc.js +11 -3
  65. package/dist/services/nifc.js.map +1 -1
  66. package/dist/services/noaa.d.ts.map +1 -1
  67. package/dist/services/noaa.js +11 -8
  68. package/dist/services/noaa.js.map +1 -1
  69. package/dist/services/nominatim.d.ts +62 -0
  70. package/dist/services/nominatim.d.ts.map +1 -0
  71. package/dist/services/nominatim.js +254 -0
  72. package/dist/services/nominatim.js.map +1 -0
  73. package/dist/services/openmeteo.d.ts.map +1 -1
  74. package/dist/services/openmeteo.js +16 -11
  75. package/dist/services/openmeteo.js.map +1 -1
  76. package/dist/types/noaa.d.ts +22 -7
  77. package/dist/types/noaa.d.ts.map +1 -1
  78. package/dist/types/nominatim.d.ts +72 -0
  79. package/dist/types/nominatim.d.ts.map +1 -0
  80. package/dist/types/nominatim.js +6 -0
  81. package/dist/types/nominatim.js.map +1 -0
  82. package/dist/types/savedLocations.d.ts +58 -0
  83. package/dist/types/savedLocations.d.ts.map +1 -0
  84. package/dist/types/savedLocations.js +5 -0
  85. package/dist/types/savedLocations.js.map +1 -0
  86. package/dist/utils/geography.d.ts +17 -0
  87. package/dist/utils/geography.d.ts.map +1 -1
  88. package/dist/utils/geography.js +56 -0
  89. package/dist/utils/geography.js.map +1 -1
  90. package/dist/utils/locationResolver.d.ts +25 -0
  91. package/dist/utils/locationResolver.d.ts.map +1 -0
  92. package/dist/utils/locationResolver.js +70 -0
  93. package/dist/utils/locationResolver.js.map +1 -0
  94. package/package.json +6 -7
package/README.md CHANGED
@@ -30,6 +30,14 @@ An MCP (Model Context Protocol) server that provides **global weather data** to
30
30
  - Support for cities, airports, landmarks, and regions globally
31
31
  - Detailed metadata: timezone, elevation, population, country
32
32
  - Enables natural language queries: "What's the weather in Tokyo?"
33
+ - **Saved Locations**: Save and reuse favorite locations (NEW in v1.7.0)
34
+ - Save frequently used locations with simple aliases ("home", "work", "cabin")
35
+ - Use saved locations by name instead of coordinates in all weather tools
36
+ - Tag locations with activities ("boating", "hiking", "skiing") for contextual weather info
37
+ - Automatic geocoding when saving (just provide location name)
38
+ - Persistent storage in `~/.weather-mcp/locations.json`
39
+ - Manage locations: save, list, view details, remove
40
+ - Makes queries natural: "What's the weather at home?" instead of providing coordinates
33
41
  - **Climate Normals - Historical Context**: Compare weather to 30-year averages (NEW in v1.2.0)
34
42
  - **Optional enhancement** for current conditions and forecasts (`include_normals=true`)
35
43
  - Shows normal high/low temperatures and precipitation for comparison
@@ -161,6 +169,28 @@ The cache automatically stores and retrieves weather data with intelligent expir
161
169
 
162
170
  ### Configuration
163
171
 
172
+ **For most users: No configuration needed!** The server works out of the box with sensible defaults and requires no API keys.
173
+
174
+ #### Optional: Environment Variables
175
+
176
+ To customize server behavior, copy the example configuration file:
177
+
178
+ ```bash
179
+ cp .env.example .env
180
+ ```
181
+
182
+ Then edit `.env` to adjust settings as needed. See [`.env.example`](./.env.example) for comprehensive documentation on all available options.
183
+
184
+ **What you can configure:**
185
+ - **Tool Selection** - Choose which MCP tools to expose (basic/standard/full/all presets)
186
+ - **Cache Settings** - Adjust cache size and enable/disable caching
187
+ - **API Configuration** - Set request timeouts
188
+ - **Logging** - Control log verbosity levels
189
+ - **Optional API Tokens** - Add NCEI token for official US climate normals (falls back to free Open-Meteo data)
190
+ - **Lightning Detection** - Configure alternative MQTT broker (optional)
191
+
192
+ All settings have sensible defaults and can be omitted entirely.
193
+
164
194
  #### Tool Selection (NEW in v1.4.0)
165
195
 
166
196
  Control which MCP tools are exposed to reduce context overhead and customize functionality. By default, only **basic** tools are enabled.
@@ -169,25 +199,16 @@ Control which MCP tools are exposed to reduce context overhead and customize fun
169
199
  - `basic` (default): Essential weather tools (5 tools) - forecast, current_conditions, alerts, search_location, check_service_status
170
200
  - `standard`: Basic + historical_weather (6 tools)
171
201
  - `full`: Standard + air_quality (7 tools)
172
- - `all`: All available tools (12 tools) - includes marine_conditions, weather_imagery, lightning_activity, river_conditions, wildfire_info
202
+ - `all`: All available tools (16 tools) - includes marine_conditions, weather_imagery, lightning_activity, river_conditions, wildfire_info, save_location, list_saved_locations, get_saved_location, remove_saved_location
173
203
 
174
204
  **Configuration Examples:**
175
205
 
176
206
  ```bash
177
- # Use a preset
178
- export ENABLED_TOOLS=full
179
-
180
- # Select specific tools
181
- export ENABLED_TOOLS=forecast,current,alerts,air_quality
182
-
183
- # Add tools to a preset
184
- export ENABLED_TOOLS=basic,+historical,+air_quality
185
-
186
- # Remove tools from a preset
187
- export ENABLED_TOOLS=all,-marine
188
-
189
- # Complex combinations
190
- export ENABLED_TOOLS=standard,+air_quality,-alerts
207
+ # In .env file or MCP client config
208
+ ENABLED_TOOLS=full # Use a preset
209
+ ENABLED_TOOLS=forecast,current,alerts,air_quality # Specific tools only
210
+ ENABLED_TOOLS=basic,+historical,+air_quality # Add to preset
211
+ ENABLED_TOOLS=all,-marine # Remove from preset
191
212
  ```
192
213
 
193
214
  **Tool Aliases:**
@@ -198,20 +219,24 @@ Short names are supported: `forecast`, `current`, `conditions`, `alerts`, `warni
198
219
  - **Better Security**: Only expose necessary functionality
199
220
  - **Customization**: Tailor the server to your specific use case
200
221
 
201
- #### Cache Configuration
222
+ #### MCP Client Configuration
202
223
 
203
- Caching is **enabled by default** with sensible settings. To customize:
224
+ You can also set environment variables directly in your MCP client configuration file instead of using a `.env` file:
204
225
 
205
- ```bash
206
- # Disable caching (not recommended)
207
- export CACHE_ENABLED=false
208
-
209
- # Adjust maximum cache size (default: 1000 entries)
210
- export CACHE_MAX_SIZE=1500
211
-
212
- # Optional: NOAA NCEI API token for official climate normals (US only, NEW in v1.2.0)
213
- # Falls back to Open-Meteo computed normals if not configured
214
- export NCEI_API_TOKEN=your_token_here
226
+ ```json
227
+ {
228
+ "mcpServers": {
229
+ "weather": {
230
+ "command": "npx",
231
+ "args": ["-y", "@dangahagan/weather-mcp@latest"],
232
+ "env": {
233
+ "ENABLED_TOOLS": "full",
234
+ "CACHE_MAX_SIZE": "2000",
235
+ "LOG_LEVEL": "1"
236
+ }
237
+ }
238
+ }
239
+ }
215
240
  ```
216
241
 
217
242
  **Note on Climate Normals (v1.2.0):**
@@ -220,6 +245,25 @@ export NCEI_API_TOKEN=your_token_here
220
245
  - Get a free token at: https://www.ncdc.noaa.gov/cdo-web/token
221
246
  - If NCEI token is configured but unavailable, the system automatically falls back to Open-Meteo
222
247
 
248
+ #### Saved Locations (NEW in v1.7.0)
249
+
250
+ The saved locations feature stores your favorite places (like "home", "work", "cabin") for easy reuse in weather queries. No configuration needed - it works automatically!
251
+
252
+ **Storage Location:**
253
+ - Data stored in: `~/.weather-mcp/locations.json`
254
+ - Directory created automatically on first save
255
+ - File is human-readable JSON (can be backed up or edited manually)
256
+
257
+ **Features:**
258
+ - No limit on number of saved locations
259
+ - Tag locations with activities (e.g., "boating", "hiking") to help AI provide relevant weather info
260
+ - Persistent across MCP server restarts
261
+ - Portable - copy the file to migrate locations to another machine
262
+
263
+ **Learn More:**
264
+ - See [save_location](#13-save_location-new-in-v170) for usage instructions
265
+ - See [Using Saved Locations](#using-saved-locations-with-weather-tools) for examples
266
+
223
267
  ### Monitoring
224
268
 
225
269
  Use the `check_service_status` tool to view cache statistics including:
@@ -268,7 +312,7 @@ If you prefer to build from source:
268
312
 
269
313
  1. Clone the repository:
270
314
  ```bash
271
- git clone https://github.com/dgahagan/weather-mcp.git
315
+ git clone https://github.com/weather-mcp/weather-mcp.git
272
316
  cd weather-mcp
273
317
  ```
274
318
 
@@ -282,6 +326,14 @@ npm install
282
326
  npm run build
283
327
  ```
284
328
 
329
+ 4. (Optional) Configure environment variables:
330
+ ```bash
331
+ cp .env.example .env
332
+ # Edit .env to customize settings (all optional)
333
+ ```
334
+
335
+ See the [Configuration](#configuration) section for details.
336
+
285
337
  ## Upgrading to Latest Version
286
338
 
287
339
  ### Upgrading npm Installation
@@ -333,7 +385,7 @@ npm run build
333
385
  You can verify your installed version by checking:
334
386
  - npm: `npm list -g @dangahagan/weather-mcp`
335
387
  - Source: `git describe --tags` or check `package.json`
336
- - Latest release: https://github.com/dgahagan/weather-mcp/releases
388
+ - Latest release: https://github.com/weather-mcp/weather-mcp/releases
337
389
 
338
390
  ## Usage with AI Assistants
339
391
 
@@ -795,6 +847,136 @@ Provides critical wildfire monitoring and safety information using NIFC (Nationa
795
847
 
796
848
  **Note:** Data from NIFC WFIGS (Wildland Fire Interagency Geospatial Services). Always consult official sources for evacuation orders at https://inciweb.nwcg.gov/
797
849
 
850
+ ### 13. save_location (NEW in v1.7.0)
851
+ Save a location with an alias for easy reuse in weather queries.
852
+
853
+ **Parameters:**
854
+ - `alias` (required): Short name for the location (e.g., "home", "work", "cabin"). Max 50 characters.
855
+ - `location_query` (optional): Location to geocode and save (e.g., "Seattle, WA", "Paris, France"). Not required if latitude/longitude provided.
856
+ - `latitude` (optional): Latitude if providing coordinates directly. Not required if location_query provided.
857
+ - `longitude` (optional): Longitude if providing coordinates directly. Not required if location_query provided.
858
+ - `name` (optional): Display name (required when using latitude/longitude directly)
859
+ - `activities` (optional): Activities you do at this location (e.g., ["boating", "fishing"]). Helps AI provide relevant weather information. Each activity max 50 characters.
860
+
861
+ **Description:**
862
+ Saves a location to persistent storage (`~/.weather-mcp/locations.json`) for easy reuse. Accepts either a location query (which will be automatically geocoded using Nominatim/OpenStreetMap) or direct coordinates. Once saved, the location can be used in any weather tool by providing `location_name` instead of coordinates.
863
+
864
+ **Smart Updates:** If the alias already exists and you only provide `name` and/or `activities` (without location details), it will update just those fields while preserving all coordinates and metadata. This makes it easy to add activities or rename locations without re-specifying the full address.
865
+
866
+ **Examples:**
867
+ ```
868
+ "Save my home location in Seattle, WA"
869
+ → save_location(alias="home", location_query="Seattle, WA")
870
+
871
+ "Save the cabin at Lake Tahoe"
872
+ → save_location(alias="cabin", location_query="Lake Tahoe, CA")
873
+
874
+ "Save coordinates 47.6062, -122.3321 as my office"
875
+ → save_location(alias="office", latitude=47.6062, longitude=-122.3321, name="Seattle Office")
876
+
877
+ "Save the lake house where we go boating and fishing"
878
+ → save_location(alias="lake_house", location_query="Lake Tahoe, CA", activities=["boating", "fishing"])
879
+
880
+ "Save my favorite hiking spot"
881
+ → save_location(alias="trail", location_query="Mt. Rainier, WA", activities=["hiking", "camping", "photography"])
882
+
883
+ "Add more activities to the cabin" (smart update - no location needed)
884
+ → save_location(alias="cabin", activities=["boating", "fishing", "hiking", "swimming"])
885
+
886
+ "Rename my campsite" (smart update - no location needed)
887
+ → save_location(alias="campsite", name="Yosemite Valley Campground")
888
+ ```
889
+
890
+ **Returns:**
891
+ - Confirmation of save with location details
892
+ - Coordinates, timezone, and administrative region
893
+ - Usage examples showing how to use with weather tools
894
+
895
+ ### 14. list_saved_locations (NEW in v1.7.0)
896
+ View all saved locations.
897
+
898
+ **Parameters:** None
899
+
900
+ **Description:**
901
+ Lists all locations saved in your persistent storage with their aliases, names, coordinates, and save dates. Helpful for seeing what location names are available for use with weather tools.
902
+
903
+ **Examples:**
904
+ ```
905
+ "Show my saved locations"
906
+ "What locations do I have saved?"
907
+ "List all my saved places"
908
+ ```
909
+
910
+ **Returns:**
911
+ - List of all saved locations with full details
912
+ - Usage examples for each location
913
+ - Total count of saved locations
914
+
915
+ ### 15. get_saved_location (NEW in v1.7.0)
916
+ Get details for a specific saved location.
917
+
918
+ **Parameters:**
919
+ - `alias` (required): The name of the saved location to retrieve (e.g., "home", "work")
920
+
921
+ **Description:**
922
+ Retrieves detailed information about a specific saved location, including coordinates, timezone, region information, and save/update timestamps.
923
+
924
+ **Examples:**
925
+ ```
926
+ "Show details for my home location"
927
+ "What are the coordinates for my cabin?"
928
+ "Get info about my work location"
929
+ ```
930
+
931
+ **Returns:**
932
+ - Location name and coordinates
933
+ - Timezone and administrative regions
934
+ - Save and update timestamps
935
+ - Usage examples
936
+
937
+ ### 16. remove_saved_location (NEW in v1.7.0)
938
+ Remove a saved location.
939
+
940
+ **Parameters:**
941
+ - `alias` (required): The name of the saved location to remove (e.g., "home", "work")
942
+
943
+ **Description:**
944
+ Permanently removes a saved location from storage. The location data is deleted and can no longer be used with weather tools unless saved again.
945
+
946
+ **Examples:**
947
+ ```
948
+ "Remove my work location"
949
+ "Delete the cabin from saved locations"
950
+ "Remove home"
951
+ ```
952
+
953
+ **Returns:**
954
+ - Confirmation of removal
955
+ - Count of remaining saved locations
956
+
957
+ ## Using Saved Locations with Weather Tools
958
+
959
+ Once you've saved locations, you can use them with any weather tool by providing `location_name` instead of coordinates:
960
+
961
+ **Examples:**
962
+ ```
963
+ # Instead of:
964
+ get_forecast(latitude=47.6062, longitude=-122.3321)
965
+
966
+ # You can use:
967
+ get_forecast(location_name="home")
968
+
969
+ # Natural language queries work too:
970
+ "What's the weather forecast at home?"
971
+ "How's the air quality at my cabin?"
972
+ "Are there any weather alerts for my work location?"
973
+ ```
974
+
975
+ **Currently Supported Tools:**
976
+ - `get_forecast` - Weather forecasts using saved locations
977
+
978
+ **Coming Soon:** Support for saved locations in all weather tools (current conditions, alerts, air quality, marine conditions, etc.)
979
+
798
980
  ## Error Handling & Service Status
799
981
 
800
982
  ### Enhanced Error Messages
@@ -904,7 +1086,7 @@ npx tsx tests/test_noaa_api.ts
904
1086
 
905
1087
  ### Manual Testing with Claude Code
906
1088
 
907
- See [TESTING_GUIDE.md](./docs/TESTING_GUIDE.md) for comprehensive manual testing instructions including:
1089
+ See [TESTING_GUIDE.md](./docs/testing/TESTING_GUIDE.md) for comprehensive manual testing instructions including:
908
1090
  - Setup steps for MCP clients
909
1091
  - Test cases for all tools
910
1092
  - Error handling verification
@@ -1107,6 +1289,43 @@ To report a security vulnerability, please see our [Security Policy](./SECURITY.
1107
1289
  - Response timeline commitments (48hr acknowledgment, 7-day assessment)
1108
1290
  - Security best practices for users and developers
1109
1291
 
1292
+ ## Documentation
1293
+
1294
+ 📚 **[Complete Documentation Index](./docs/README.md)** - Comprehensive navigation guide to all project documentation
1295
+
1296
+ ### Quick Links
1297
+
1298
+ **For Users:**
1299
+ - [Client Setup Guide](./docs/CLIENT_SETUP.md) - Setup instructions for 8 different MCP clients
1300
+ - [Testing Guide](./docs/testing/TESTING_GUIDE.md) - Manual testing procedures
1301
+ - [Error Handling](./docs/ERROR_HANDLING.md) - Enhanced error handling features
1302
+
1303
+ **For Developers:**
1304
+ - [Contributing Guidelines](./CONTRIBUTING.md) - How to contribute
1305
+ - [Development Guide](./CLAUDE.md) - AI assistant development guide
1306
+ - [Code Review](./docs/development/CODE_REVIEW.md) - Code quality analysis
1307
+ - [Security Audit](./docs/development/SECURITY_AUDIT_V1.6.md) - Security assessment
1308
+
1309
+ **Planning & Roadmap:**
1310
+ - [Implementation Plan](./docs/planning/IMPLEMENTATION_PLAN.md) - Project roadmap
1311
+ - [Future Enhancements](./docs/planning/FUTURE_ENHANCEMENTS.md) - Planned features
1312
+ - [Roadmap](./docs/planning/ROADMAP.md) - Long-term plans
1313
+
1314
+ **Testing & Quality:**
1315
+ - [Test Suite](./docs/testing/TEST_SUITE_README.md) - Test overview
1316
+ - [Test Coverage](./docs/testing/TEST_COVERAGE_ANALYSIS_2025.md) - Latest coverage analysis
1317
+ - [Test Recommendations](./docs/testing/TEST_RECOMMENDATIONS.md) - Improvement suggestions
1318
+
1319
+ **Analytics (Optional):**
1320
+ - [Analytics Plan](./docs/analytics/ANALYTICS_MCP_PLAN.md) - Privacy-first analytics
1321
+ - [Analytics Security](./docs/analytics/MCP_ANALYTICS_SECURITY_GUIDE.md) - Security implementation guide
1322
+ - [Local Analytics](./docs/analytics/LOCAL_ANALYTICS_GUIDE.md) - Setup guide
1323
+
1324
+ **Technical Documentation:**
1325
+ - [NOAA API Research](./docs/NOAA_API_RESEARCH.md) - NOAA API integration details
1326
+ - [Historical Data Plan](./docs/HISTORICAL_DATA_PLAN.md) - Historical weather implementation
1327
+ - [MCP Best Practices](./docs/MCP_BEST_PRACTICES.md) - MCP protocol guidelines
1328
+
1110
1329
  ## License
1111
1330
 
1112
1331
  MIT
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Data anonymization utilities for privacy-first analytics
3
+ * Ensures no PII is collected as per docs/ANALYTICS_MCP_PLAN.md
4
+ */
5
+ import { AnalyticsEvent, AnalyticsLevel } from './types.js';
6
+ /**
7
+ * Raw event data before anonymization
8
+ * Includes all possible fields that might be collected
9
+ */
10
+ interface RawEventData {
11
+ version: string;
12
+ tool: string;
13
+ status: 'success' | 'error';
14
+ timestamp_hour: string;
15
+ analytics_level?: AnalyticsLevel;
16
+ error_type?: string;
17
+ response_time_ms?: number;
18
+ service?: string;
19
+ cache_hit?: boolean;
20
+ retry_count?: number;
21
+ country?: string;
22
+ parameters?: Record<string, unknown>;
23
+ session_id?: string;
24
+ sequence_number?: number;
25
+ }
26
+ /**
27
+ * Anonymize event data based on analytics level
28
+ * Strips sensitive information and ensures privacy compliance
29
+ */
30
+ export declare function anonymizeEvent(rawData: RawEventData, level: AnalyticsLevel, salt?: string): AnalyticsEvent;
31
+ /**
32
+ * Round timestamp to nearest hour for privacy
33
+ * Prevents precise user tracking
34
+ */
35
+ export declare function roundToHour(date: Date): string;
36
+ export {};
37
+ //# sourceMappingURL=anonymizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anonymizer.d.ts","sourceRoot":"","sources":["../../src/analytics/anonymizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D;;;GAGG;AACH,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,cAAc,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,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,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,cAAc,EACrB,IAAI,CAAC,EAAE,MAAM,GACZ,cAAc,CA0ChB;AAiED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAI9C"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Data anonymization utilities for privacy-first analytics
3
+ * Ensures no PII is collected as per docs/ANALYTICS_MCP_PLAN.md
4
+ */
5
+ import crypto from 'crypto';
6
+ /**
7
+ * Anonymize event data based on analytics level
8
+ * Strips sensitive information and ensures privacy compliance
9
+ */
10
+ export function anonymizeEvent(rawData, level, salt) {
11
+ // Base event (minimal level) - always included
12
+ const baseEvent = {
13
+ version: rawData.version,
14
+ tool: rawData.tool,
15
+ status: rawData.status,
16
+ timestamp_hour: rawData.timestamp_hour,
17
+ analytics_level: 'minimal',
18
+ ...(rawData.status === 'error' && rawData.error_type ? { error_type: rawData.error_type } : {}),
19
+ };
20
+ // Return minimal level (no additional data)
21
+ if (level === 'minimal') {
22
+ return baseEvent;
23
+ }
24
+ // Standard level - add performance metrics
25
+ const standardEvent = {
26
+ ...baseEvent,
27
+ analytics_level: 'standard',
28
+ ...(rawData.response_time_ms !== undefined && { response_time_ms: rawData.response_time_ms }),
29
+ ...(rawData.service && { service: rawData.service }),
30
+ ...(rawData.cache_hit !== undefined && { cache_hit: rawData.cache_hit }),
31
+ ...(rawData.retry_count !== undefined && { retry_count: rawData.retry_count }),
32
+ ...(rawData.country && { country: rawData.country }),
33
+ };
34
+ // Return standard level
35
+ if (level === 'standard') {
36
+ return standardEvent;
37
+ }
38
+ // Detailed level - add anonymized workflow data
39
+ const detailedEvent = {
40
+ ...standardEvent,
41
+ analytics_level: 'detailed',
42
+ ...(rawData.parameters && { parameters: sanitizeParameters(rawData.parameters) }),
43
+ ...(rawData.session_id && { session_id: hashSessionId(rawData.session_id, salt) }),
44
+ ...(rawData.sequence_number !== undefined && { sequence_number: rawData.sequence_number }),
45
+ };
46
+ return detailedEvent;
47
+ }
48
+ /**
49
+ * Sanitize tool parameters - ONLY keep safe, non-identifying values
50
+ * NEVER include: coordinates, location names, user input
51
+ */
52
+ function sanitizeParameters(params) {
53
+ const safe = {};
54
+ // Allowlist of safe parameters that don't contain PII
55
+ const allowedParams = [
56
+ 'days',
57
+ 'granularity',
58
+ 'source',
59
+ 'forecast_type',
60
+ 'include_normals',
61
+ 'include_fire_weather',
62
+ 'include_severe_weather',
63
+ 'active_only',
64
+ 'limit',
65
+ 'radius',
66
+ 'units',
67
+ 'hourly',
68
+ 'daily',
69
+ ];
70
+ for (const key of allowedParams) {
71
+ if (params[key] !== undefined) {
72
+ // Only include primitive values (no objects/arrays that might contain PII)
73
+ const value = params[key];
74
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
75
+ safe[key] = value;
76
+ }
77
+ }
78
+ }
79
+ // NEVER include these (blocklist for extra safety):
80
+ // - latitude, longitude, lat, lon
81
+ // - location, address, city, state, zip, postal_code
82
+ // - user, name, email, phone
83
+ // - any user-provided strings
84
+ return safe;
85
+ }
86
+ /**
87
+ * Create one-way hash of session ID
88
+ * Cannot be reversed to identify users
89
+ */
90
+ function hashSessionId(sessionId, salt) {
91
+ // Salt should always be provided by config (auto-generated)
92
+ // Fallback to environment variable if somehow not provided
93
+ const sessionSalt = salt || process.env.ANALYTICS_SALT || '';
94
+ if (!sessionSalt) {
95
+ throw new Error('Analytics salt must be provided for session ID hashing');
96
+ }
97
+ return crypto
98
+ .createHash('sha256')
99
+ .update(sessionId + sessionSalt)
100
+ .digest('hex')
101
+ .substring(0, 16); // Shortened for storage efficiency
102
+ }
103
+ /**
104
+ * Round timestamp to nearest hour for privacy
105
+ * Prevents precise user tracking
106
+ */
107
+ export function roundToHour(date) {
108
+ const rounded = new Date(date);
109
+ rounded.setMinutes(0, 0, 0);
110
+ return rounded.toISOString();
111
+ }
112
+ //# sourceMappingURL=anonymizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anonymizer.js","sourceRoot":"","sources":["../../src/analytics/anonymizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Analytics event collector and batch manager
3
+ * Buffers events in memory and periodically flushes to analytics server
4
+ */
5
+ import { AnalyticsConfig, ToolExecutionMetadata } from './types.js';
6
+ /**
7
+ * AnalyticsCollector - Manages event buffering and batch sending
8
+ * Implements privacy-first analytics with automatic flushing
9
+ */
10
+ export declare class AnalyticsCollector {
11
+ private buffer;
12
+ private config;
13
+ private flushTimer;
14
+ private sessionId;
15
+ private sequenceNumber;
16
+ private isShuttingDown;
17
+ private consecutiveFailures;
18
+ private circuitOpen;
19
+ private circuitOpenUntil;
20
+ private readonly MAX_CONSECUTIVE_FAILURES;
21
+ private readonly CIRCUIT_BREAKER_RESET_MS;
22
+ private errorCount;
23
+ private successCount;
24
+ private readonly ERROR_THRESHOLD;
25
+ private lastFlushTime;
26
+ private flushCount;
27
+ private readonly MIN_FLUSH_INTERVAL_MS;
28
+ private readonly MAX_FLUSHES_PER_HOUR;
29
+ private readonly MAX_EVENTS_PER_MINUTE;
30
+ private recentEventTimestamps;
31
+ private readonly MAX_BUFFER_SIZE;
32
+ private readonly FLUSH_INTERVAL_MS;
33
+ constructor(config: AnalyticsConfig);
34
+ /**
35
+ * Track a tool execution event
36
+ * Fails silently - analytics should never break the application
37
+ */
38
+ trackToolCall(tool: string, status: 'success' | 'error', metadata?: ToolExecutionMetadata): Promise<void>;
39
+ /**
40
+ * Flush buffered events to analytics server
41
+ * Called automatically on timer or when buffer is full
42
+ * Implements circuit breaker pattern (3.7)
43
+ */
44
+ flush(): Promise<void>;
45
+ /**
46
+ * Start periodic flush timer
47
+ */
48
+ private startFlushTimer;
49
+ /**
50
+ * Stop flush timer
51
+ */
52
+ private stopFlushTimer;
53
+ /**
54
+ * Generate unique session ID
55
+ * Used for tracking tool call sequences in detailed mode
56
+ */
57
+ private generateSessionId;
58
+ /**
59
+ * Public shutdown method called by main shutdown handler
60
+ * Ensures buffered events are sent before process exits
61
+ */
62
+ shutdown(): Promise<void>;
63
+ /**
64
+ * Get current buffer size (for testing)
65
+ */
66
+ getBufferSize(): number;
67
+ /**
68
+ * Get session ID (for testing)
69
+ */
70
+ getSessionId(): string;
71
+ }
72
+ //# sourceMappingURL=collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/analytics/collector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAAE,eAAe,EAAkB,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEpF;;;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;IAG/B,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;gBAEvC,MAAM,EAAE,eAAe;IAanC;;;OAGG;IACU,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,GAAG,OAAO,EAC3B,QAAQ,GAAE,qBAA0B,GACnC,OAAO,CAAC,IAAI,CAAC;IA+GhB;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6EnC;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,cAAc;IAOtB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtC;;OAEG;IACI,aAAa,IAAI,MAAM;IAI9B;;OAEG;IACI,YAAY,IAAI,MAAM;CAG9B"}