@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.
- package/LICENSE +21 -0
- package/README.md +1319 -0
- package/dist/analytics/anonymizer.d.ts +37 -0
- package/dist/analytics/anonymizer.d.ts.map +1 -0
- package/dist/analytics/anonymizer.js +112 -0
- package/dist/analytics/anonymizer.js.map +1 -0
- package/dist/analytics/collector.d.ts +72 -0
- package/dist/analytics/collector.d.ts.map +1 -0
- package/dist/analytics/collector.js +282 -0
- package/dist/analytics/collector.js.map +1 -0
- package/dist/analytics/config.d.ts +15 -0
- package/dist/analytics/config.d.ts.map +1 -0
- package/dist/analytics/config.js +172 -0
- package/dist/analytics/config.js.map +1 -0
- package/dist/analytics/index.d.ts +8 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +7 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/middleware.d.ts +33 -0
- package/dist/analytics/middleware.d.ts.map +1 -0
- package/dist/analytics/middleware.js +99 -0
- package/dist/analytics/middleware.js.map +1 -0
- package/dist/analytics/transport.d.ts +11 -0
- package/dist/analytics/transport.d.ts.map +1 -0
- package/dist/analytics/transport.js +92 -0
- package/dist/analytics/transport.js.map +1 -0
- package/dist/analytics/types.d.ts +74 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics/types.js +6 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/config/api.d.ts +30 -0
- package/dist/config/api.d.ts.map +1 -0
- package/dist/config/api.js +32 -0
- package/dist/config/api.js.map +1 -0
- package/dist/config/cache.d.ts +31 -0
- package/dist/config/cache.d.ts.map +1 -0
- package/dist/config/cache.js +108 -0
- package/dist/config/cache.js.map +1 -0
- package/dist/config/displayThresholds.d.ts +83 -0
- package/dist/config/displayThresholds.d.ts.map +1 -0
- package/dist/config/displayThresholds.js +83 -0
- package/dist/config/displayThresholds.js.map +1 -0
- package/dist/config/tools.d.ts +44 -0
- package/dist/config/tools.d.ts.map +1 -0
- package/dist/config/tools.js +269 -0
- package/dist/config/tools.js.map +1 -0
- package/dist/errors/ApiError.d.ts +62 -0
- package/dist/errors/ApiError.d.ts.map +1 -0
- package/dist/errors/ApiError.js +171 -0
- package/dist/errors/ApiError.js.map +1 -0
- package/dist/handlers/airQualityHandler.d.ts +11 -0
- package/dist/handlers/airQualityHandler.d.ts.map +1 -0
- package/dist/handlers/airQualityHandler.js +154 -0
- package/dist/handlers/airQualityHandler.js.map +1 -0
- package/dist/handlers/alertsHandler.d.ts +11 -0
- package/dist/handlers/alertsHandler.d.ts.map +1 -0
- package/dist/handlers/alertsHandler.js +98 -0
- package/dist/handlers/alertsHandler.js.map +1 -0
- package/dist/handlers/currentConditionsHandler.d.ts +13 -0
- package/dist/handlers/currentConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/currentConditionsHandler.js +296 -0
- package/dist/handlers/currentConditionsHandler.js.map +1 -0
- package/dist/handlers/forecastHandler.d.ts +16 -0
- package/dist/handlers/forecastHandler.d.ts.map +1 -0
- package/dist/handlers/forecastHandler.js +454 -0
- package/dist/handlers/forecastHandler.js.map +1 -0
- package/dist/handlers/historicalWeatherHandler.d.ts +12 -0
- package/dist/handlers/historicalWeatherHandler.d.ts.map +1 -0
- package/dist/handlers/historicalWeatherHandler.js +188 -0
- package/dist/handlers/historicalWeatherHandler.js.map +1 -0
- package/dist/handlers/lightningHandler.d.ts +14 -0
- package/dist/handlers/lightningHandler.d.ts.map +1 -0
- package/dist/handlers/lightningHandler.js +258 -0
- package/dist/handlers/lightningHandler.js.map +1 -0
- package/dist/handlers/locationHandler.d.ts +12 -0
- package/dist/handlers/locationHandler.d.ts.map +1 -0
- package/dist/handlers/locationHandler.js +149 -0
- package/dist/handlers/locationHandler.js.map +1 -0
- package/dist/handlers/marineConditionsHandler.d.ts +13 -0
- package/dist/handlers/marineConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/marineConditionsHandler.js +270 -0
- package/dist/handlers/marineConditionsHandler.js.map +1 -0
- package/dist/handlers/riverConditionsHandler.d.ts +11 -0
- package/dist/handlers/riverConditionsHandler.d.ts.map +1 -0
- package/dist/handlers/riverConditionsHandler.js +176 -0
- package/dist/handlers/riverConditionsHandler.js.map +1 -0
- package/dist/handlers/savedLocationsHandler.d.ts +50 -0
- package/dist/handlers/savedLocationsHandler.d.ts.map +1 -0
- package/dist/handlers/savedLocationsHandler.js +397 -0
- package/dist/handlers/savedLocationsHandler.js.map +1 -0
- package/dist/handlers/statusHandler.d.ts +12 -0
- package/dist/handlers/statusHandler.d.ts.map +1 -0
- package/dist/handlers/statusHandler.js +115 -0
- package/dist/handlers/statusHandler.js.map +1 -0
- package/dist/handlers/weatherImageryHandler.d.ts +14 -0
- package/dist/handlers/weatherImageryHandler.d.ts.map +1 -0
- package/dist/handlers/weatherImageryHandler.js +143 -0
- package/dist/handlers/weatherImageryHandler.js.map +1 -0
- package/dist/handlers/wildfireHandler.d.ts +11 -0
- package/dist/handlers/wildfireHandler.d.ts.map +1 -0
- package/dist/handlers/wildfireHandler.js +186 -0
- package/dist/handlers/wildfireHandler.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +735 -0
- package/dist/index.js.map +1 -0
- package/dist/services/blitzortung.d.ts +67 -0
- package/dist/services/blitzortung.d.ts.map +1 -0
- package/dist/services/blitzortung.js +475 -0
- package/dist/services/blitzortung.js.map +1 -0
- package/dist/services/geocoding.d.ts +57 -0
- package/dist/services/geocoding.d.ts.map +1 -0
- package/dist/services/geocoding.js +393 -0
- package/dist/services/geocoding.js.map +1 -0
- package/dist/services/locationStore.d.ts +62 -0
- package/dist/services/locationStore.d.ts.map +1 -0
- package/dist/services/locationStore.js +201 -0
- package/dist/services/locationStore.js.map +1 -0
- package/dist/services/ncei.d.ts +61 -0
- package/dist/services/ncei.d.ts.map +1 -0
- package/dist/services/ncei.js +126 -0
- package/dist/services/ncei.js.map +1 -0
- package/dist/services/nifc.d.ts +44 -0
- package/dist/services/nifc.d.ts.map +1 -0
- package/dist/services/nifc.js +159 -0
- package/dist/services/nifc.js.map +1 -0
- package/dist/services/noaa.d.ts +161 -0
- package/dist/services/noaa.d.ts.map +1 -0
- package/dist/services/noaa.js +681 -0
- package/dist/services/noaa.js.map +1 -0
- package/dist/services/nominatim.d.ts +62 -0
- package/dist/services/nominatim.d.ts.map +1 -0
- package/dist/services/nominatim.js +254 -0
- package/dist/services/nominatim.js.map +1 -0
- package/dist/services/openmeteo.d.ts +189 -0
- package/dist/services/openmeteo.d.ts.map +1 -0
- package/dist/services/openmeteo.js +936 -0
- package/dist/services/openmeteo.js.map +1 -0
- package/dist/services/rainviewer.d.ts +37 -0
- package/dist/services/rainviewer.d.ts.map +1 -0
- package/dist/services/rainviewer.js +115 -0
- package/dist/services/rainviewer.js.map +1 -0
- package/dist/types/imagery.d.ts +82 -0
- package/dist/types/imagery.d.ts.map +1 -0
- package/dist/types/imagery.js +6 -0
- package/dist/types/imagery.js.map +1 -0
- package/dist/types/lightning.d.ts +89 -0
- package/dist/types/lightning.d.ts.map +1 -0
- package/dist/types/lightning.js +6 -0
- package/dist/types/lightning.js.map +1 -0
- package/dist/types/noaa.d.ts +535 -0
- package/dist/types/noaa.d.ts.map +1 -0
- package/dist/types/noaa.js +5 -0
- package/dist/types/noaa.js.map +1 -0
- package/dist/types/nominatim.d.ts +72 -0
- package/dist/types/nominatim.d.ts.map +1 -0
- package/dist/types/nominatim.js +6 -0
- package/dist/types/nominatim.js.map +1 -0
- package/dist/types/openmeteo.d.ts +583 -0
- package/dist/types/openmeteo.d.ts.map +1 -0
- package/dist/types/openmeteo.js +6 -0
- package/dist/types/openmeteo.js.map +1 -0
- package/dist/types/savedLocations.d.ts +58 -0
- package/dist/types/savedLocations.d.ts.map +1 -0
- package/dist/types/savedLocations.js +5 -0
- package/dist/types/savedLocations.js.map +1 -0
- package/dist/types/wildfire.d.ts +83 -0
- package/dist/types/wildfire.d.ts.map +1 -0
- package/dist/types/wildfire.js +5 -0
- package/dist/types/wildfire.js.map +1 -0
- package/dist/utils/airQuality.d.ts +54 -0
- package/dist/utils/airQuality.d.ts.map +1 -0
- package/dist/utils/airQuality.js +251 -0
- package/dist/utils/airQuality.js.map +1 -0
- package/dist/utils/cache.d.ts +69 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +164 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/distance.d.ts +25 -0
- package/dist/utils/distance.d.ts.map +1 -0
- package/dist/utils/distance.js +40 -0
- package/dist/utils/distance.js.map +1 -0
- package/dist/utils/fireWeather.d.ts +76 -0
- package/dist/utils/fireWeather.d.ts.map +1 -0
- package/dist/utils/fireWeather.js +243 -0
- package/dist/utils/fireWeather.js.map +1 -0
- package/dist/utils/geography.d.ts +79 -0
- package/dist/utils/geography.d.ts.map +1 -0
- package/dist/utils/geography.js +266 -0
- package/dist/utils/geography.js.map +1 -0
- package/dist/utils/geohash.d.ts +62 -0
- package/dist/utils/geohash.d.ts.map +1 -0
- package/dist/utils/geohash.js +146 -0
- package/dist/utils/geohash.js.map +1 -0
- package/dist/utils/locationResolver.d.ts +34 -0
- package/dist/utils/locationResolver.d.ts.map +1 -0
- package/dist/utils/locationResolver.js +120 -0
- package/dist/utils/locationResolver.js.map +1 -0
- package/dist/utils/logger.d.ts +75 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +153 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/marine.d.ts +59 -0
- package/dist/utils/marine.d.ts.map +1 -0
- package/dist/utils/marine.js +215 -0
- package/dist/utils/marine.js.map +1 -0
- package/dist/utils/normals.d.ts +86 -0
- package/dist/utils/normals.d.ts.map +1 -0
- package/dist/utils/normals.js +223 -0
- package/dist/utils/normals.js.map +1 -0
- package/dist/utils/snow.d.ts +45 -0
- package/dist/utils/snow.d.ts.map +1 -0
- package/dist/utils/snow.js +144 -0
- package/dist/utils/snow.js.map +1 -0
- package/dist/utils/temperatureConversion.d.ts +12 -0
- package/dist/utils/temperatureConversion.d.ts.map +1 -0
- package/dist/utils/temperatureConversion.js +17 -0
- package/dist/utils/temperatureConversion.js.map +1 -0
- package/dist/utils/timezone.d.ts +56 -0
- package/dist/utils/timezone.d.ts.map +1 -0
- package/dist/utils/timezone.js +167 -0
- package/dist/utils/timezone.js.map +1 -0
- package/dist/utils/units.d.ts +69 -0
- package/dist/utils/units.d.ts.map +1 -0
- package/dist/utils/units.js +158 -0
- package/dist/utils/units.js.map +1 -0
- package/dist/utils/validation.d.ts +89 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +177 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/utils/version.d.ts +15 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +24 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +74 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,735 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Weather MCP Server
|
|
4
|
+
* Provides weather data from NOAA API to AI systems via Model Context Protocol
|
|
5
|
+
*/
|
|
6
|
+
// Load environment variables from .env file (for local development)
|
|
7
|
+
import 'dotenv/config';
|
|
8
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { NOAAService } from './services/noaa.js';
|
|
12
|
+
import { OpenMeteoService } from './services/openmeteo.js';
|
|
13
|
+
import { NominatimService } from './services/nominatim.js';
|
|
14
|
+
import { NCEIService } from './services/ncei.js';
|
|
15
|
+
import { NIFCService } from './services/nifc.js';
|
|
16
|
+
import { GeocodingService } from './services/geocoding.js';
|
|
17
|
+
import { LocationStore } from './services/locationStore.js';
|
|
18
|
+
import { CacheConfig } from './config/cache.js';
|
|
19
|
+
import { toolConfig } from './config/tools.js';
|
|
20
|
+
import { logger } from './utils/logger.js';
|
|
21
|
+
import { formatErrorForUser } from './errors/ApiError.js';
|
|
22
|
+
import { handleGetForecast } from './handlers/forecastHandler.js';
|
|
23
|
+
import { handleGetAlerts } from './handlers/alertsHandler.js';
|
|
24
|
+
import { handleGetHistoricalWeather } from './handlers/historicalWeatherHandler.js';
|
|
25
|
+
import { handleCheckServiceStatus } from './handlers/statusHandler.js';
|
|
26
|
+
import { handleSearchLocation } from './handlers/locationHandler.js';
|
|
27
|
+
import { handleGetAirQuality } from './handlers/airQualityHandler.js';
|
|
28
|
+
import { handleGetMarineConditions } from './handlers/marineConditionsHandler.js';
|
|
29
|
+
import { getWeatherImagery, formatWeatherImageryResponse } from './handlers/weatherImageryHandler.js';
|
|
30
|
+
import { getLightningActivity, formatLightningActivityResponse } from './handlers/lightningHandler.js';
|
|
31
|
+
import { handleGetRiverConditions } from './handlers/riverConditionsHandler.js';
|
|
32
|
+
import { handleGetWildfireInfo } from './handlers/wildfireHandler.js';
|
|
33
|
+
import { handleSaveLocation, handleListSavedLocations, handleGetSavedLocation, handleRemoveSavedLocation } from './handlers/savedLocationsHandler.js';
|
|
34
|
+
import { withAnalytics, analytics } from './analytics/index.js';
|
|
35
|
+
/**
|
|
36
|
+
* Server information
|
|
37
|
+
*/
|
|
38
|
+
import { readFileSync } from 'fs';
|
|
39
|
+
import { fileURLToPath } from 'url';
|
|
40
|
+
import { dirname, join } from 'path';
|
|
41
|
+
// Read version from package.json to ensure single source of truth
|
|
42
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
43
|
+
const __dirname = dirname(__filename);
|
|
44
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
45
|
+
const SERVER_NAME = 'weather-mcp';
|
|
46
|
+
const SERVER_VERSION = packageJson.version;
|
|
47
|
+
/**
|
|
48
|
+
* Redact sensitive fields from tool arguments before logging
|
|
49
|
+
* Removes PII like coordinates, location names, addresses
|
|
50
|
+
*/
|
|
51
|
+
function redactSensitiveFields(args) {
|
|
52
|
+
if (typeof args !== 'object' || args === null) {
|
|
53
|
+
return args;
|
|
54
|
+
}
|
|
55
|
+
const redacted = {};
|
|
56
|
+
const sensitiveFields = [
|
|
57
|
+
'latitude', 'longitude', 'lat', 'lon',
|
|
58
|
+
'location', 'city', 'city_name', 'state', 'address', 'query',
|
|
59
|
+
'zipcode', 'postalCode', 'place', 'coordinates'
|
|
60
|
+
];
|
|
61
|
+
for (const [key, value] of Object.entries(args)) {
|
|
62
|
+
if (sensitiveFields.includes(key)) {
|
|
63
|
+
redacted[key] = '[REDACTED]';
|
|
64
|
+
}
|
|
65
|
+
else if (typeof value === 'object' && value !== null) {
|
|
66
|
+
redacted[key] = redactSensitiveFields(value);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
redacted[key] = value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return redacted;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Initialize the NOAA service
|
|
76
|
+
*/
|
|
77
|
+
const noaaService = new NOAAService({
|
|
78
|
+
userAgent: `weather-mcp/${SERVER_VERSION} (https://github.com/weather-mcp/weather-mcp)`
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* Initialize the Open-Meteo service for historical data
|
|
82
|
+
* No API key required - free for non-commercial use
|
|
83
|
+
*/
|
|
84
|
+
const openMeteoService = new OpenMeteoService();
|
|
85
|
+
/**
|
|
86
|
+
* Initialize the Nominatim service for geocoding
|
|
87
|
+
* No API key required - uses OpenStreetMap data
|
|
88
|
+
* Better coverage for small towns and villages than GeoNames
|
|
89
|
+
* Rate limited to 1 request/second as per OSM usage policy
|
|
90
|
+
*/
|
|
91
|
+
const nominatimService = new NominatimService();
|
|
92
|
+
/**
|
|
93
|
+
* Initialize the LocationStore for managing saved/favorite locations
|
|
94
|
+
* Stores locations in ~/.weather-mcp/locations.json
|
|
95
|
+
* No configuration required
|
|
96
|
+
*/
|
|
97
|
+
const locationStore = new LocationStore();
|
|
98
|
+
/**
|
|
99
|
+
* Initialize the NCEI service for climate normals (optional)
|
|
100
|
+
* Requires free API token from https://www.ncdc.noaa.gov/cdo-web/token
|
|
101
|
+
* Falls back to Open-Meteo computed normals if not configured
|
|
102
|
+
*/
|
|
103
|
+
const nceiService = new NCEIService();
|
|
104
|
+
/**
|
|
105
|
+
* Initialize the NIFC service for wildfire data
|
|
106
|
+
* No API key required - uses public ArcGIS REST API
|
|
107
|
+
*/
|
|
108
|
+
const nifcService = new NIFCService();
|
|
109
|
+
/**
|
|
110
|
+
* Initialize the Geocoding service with multi-provider support
|
|
111
|
+
* No API key required - uses Census.gov, Nominatim, and Open-Meteo
|
|
112
|
+
* Automatic fallback strategy for maximum reliability
|
|
113
|
+
*/
|
|
114
|
+
const geocodingService = new GeocodingService();
|
|
115
|
+
/**
|
|
116
|
+
* Create MCP server instance
|
|
117
|
+
*/
|
|
118
|
+
const server = new Server({
|
|
119
|
+
name: SERVER_NAME,
|
|
120
|
+
version: SERVER_VERSION,
|
|
121
|
+
}, {
|
|
122
|
+
capabilities: {
|
|
123
|
+
tools: {},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
/**
|
|
127
|
+
* Tool definitions - each tool defined separately for conditional registration
|
|
128
|
+
*/
|
|
129
|
+
const TOOL_DEFINITIONS = {
|
|
130
|
+
get_forecast: {
|
|
131
|
+
name: 'get_forecast',
|
|
132
|
+
description: 'Get future weather forecast for a location (global coverage). Use this for upcoming weather predictions (e.g., "tomorrow", "this week", "next 7 days", "hourly forecast") and for current or today\'s weather when a dedicated current-conditions tool is unavailable. Returns forecast data including temperature, precipitation, wind, conditions, and sunrise/sunset times. Supports both daily and hourly granularity. Automatically selects best data source: NOAA for US locations (more detailed), Open-Meteo for international locations. For past weather, use get_historical_weather. Can use coordinates, a saved location name (e.g., location_name="home"), or a city/place name (e.g., city_name="Paris, France") which is geocoded automatically using the same service as search_location. If this tool returns an error, check the error message for status page links and consider using check_service_status to verify API availability.',
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
latitude: {
|
|
137
|
+
type: 'number',
|
|
138
|
+
description: 'Latitude of the location (-90 to 90). Not required if location_name or city_name is provided.',
|
|
139
|
+
minimum: -90,
|
|
140
|
+
maximum: 90
|
|
141
|
+
},
|
|
142
|
+
longitude: {
|
|
143
|
+
type: 'number',
|
|
144
|
+
description: 'Longitude of the location (-180 to 180). Not required if location_name or city_name is provided.',
|
|
145
|
+
minimum: -180,
|
|
146
|
+
maximum: 180
|
|
147
|
+
},
|
|
148
|
+
location_name: {
|
|
149
|
+
type: 'string',
|
|
150
|
+
description: 'Name of a saved location (e.g., "home", "cabin"). Use this instead of latitude/longitude to reference a saved location. List saved locations with list_saved_locations.'
|
|
151
|
+
},
|
|
152
|
+
city_name: {
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'City or place name to geocode (e.g., "Seattle, WA", "Paris, France"). For cities in China, use pinyin only (e.g., "Beijing", "Shanghai"; not Chinese characters). Uses the same geocoding as search_location. Not required if latitude/longitude or location_name is provided.'
|
|
155
|
+
},
|
|
156
|
+
days: {
|
|
157
|
+
type: 'number',
|
|
158
|
+
description: 'Number of days to include in forecast (1-16 for global, 1-7 for US NOAA, default: 7)',
|
|
159
|
+
minimum: 1,
|
|
160
|
+
maximum: 16,
|
|
161
|
+
default: 7
|
|
162
|
+
},
|
|
163
|
+
granularity: {
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'Forecast granularity: "daily" for day/night periods or "hourly" for hour-by-hour detail (default: "daily")',
|
|
166
|
+
enum: ['daily', 'hourly'],
|
|
167
|
+
default: 'daily'
|
|
168
|
+
},
|
|
169
|
+
include_precipitation_probability: {
|
|
170
|
+
type: 'boolean',
|
|
171
|
+
description: 'Include precipitation probability in the forecast output (default: true)',
|
|
172
|
+
default: true
|
|
173
|
+
},
|
|
174
|
+
include_severe_weather: {
|
|
175
|
+
type: 'boolean',
|
|
176
|
+
description: 'Include severe weather probabilities such as thunderstorm chance, wind gust probabilities, and tropical storm/hurricane risks (default: false, US/NOAA only)',
|
|
177
|
+
default: false
|
|
178
|
+
},
|
|
179
|
+
include_normals: {
|
|
180
|
+
type: 'boolean',
|
|
181
|
+
description: 'Include climate normals (30-year averages) for comparison with forecasted temperatures (default: false, daily forecasts only). Shows normal high/low and departure from normal for the first forecast day.',
|
|
182
|
+
default: false
|
|
183
|
+
},
|
|
184
|
+
source: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'Data source: "auto" (default, selects NOAA for US or Open-Meteo for international), "noaa" (US only), or "openmeteo" (global)',
|
|
187
|
+
enum: ['auto', 'noaa', 'openmeteo'],
|
|
188
|
+
default: 'auto'
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
required: []
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
get_alerts: {
|
|
195
|
+
name: 'get_alerts',
|
|
196
|
+
description: 'Get active weather alerts, watches, warnings, and advisories for a location (US only). Use this for safety-critical weather information when asked about "any alerts?", "weather warnings?", "is it safe?", "dangerous weather?", or "weather watches?". Returns severity, urgency, certainty, effective/expiration times, and affected areas. For forecast data, use get_forecast instead. If this tool returns an error, check the error message for status page links and consider using check_service_status to verify API availability.',
|
|
197
|
+
inputSchema: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
properties: {
|
|
200
|
+
latitude: {
|
|
201
|
+
type: 'number',
|
|
202
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
203
|
+
minimum: -90,
|
|
204
|
+
maximum: 90
|
|
205
|
+
},
|
|
206
|
+
longitude: {
|
|
207
|
+
type: 'number',
|
|
208
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
209
|
+
minimum: -180,
|
|
210
|
+
maximum: 180
|
|
211
|
+
},
|
|
212
|
+
active_only: {
|
|
213
|
+
type: 'boolean',
|
|
214
|
+
description: 'Whether to show only active alerts (default: true)',
|
|
215
|
+
default: true
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
required: ['latitude', 'longitude']
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
get_historical_weather: {
|
|
222
|
+
name: 'get_historical_weather',
|
|
223
|
+
description: 'Get historical weather data for a specific date range in the past. Use this when the user asks about weather on specific past dates (e.g., "yesterday", "last week", "November 4, 2024", "30 years ago"). Automatically uses NOAA API for recent dates (last 7 days, US only) or Open-Meteo API for older dates (worldwide, back to 1940). For upcoming or today\'s weather, use get_forecast instead. If this tool returns an error, check the error message for status page links and consider using check_service_status to verify API availability.',
|
|
224
|
+
inputSchema: {
|
|
225
|
+
type: 'object',
|
|
226
|
+
properties: {
|
|
227
|
+
latitude: {
|
|
228
|
+
type: 'number',
|
|
229
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
230
|
+
minimum: -90,
|
|
231
|
+
maximum: 90
|
|
232
|
+
},
|
|
233
|
+
longitude: {
|
|
234
|
+
type: 'number',
|
|
235
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
236
|
+
minimum: -180,
|
|
237
|
+
maximum: 180
|
|
238
|
+
},
|
|
239
|
+
start_date: {
|
|
240
|
+
type: 'string',
|
|
241
|
+
description: 'Start date in ISO format (YYYY-MM-DD or ISO 8601 datetime)',
|
|
242
|
+
},
|
|
243
|
+
end_date: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: 'End date in ISO format (YYYY-MM-DD or ISO 8601 datetime)',
|
|
246
|
+
},
|
|
247
|
+
limit: {
|
|
248
|
+
type: 'number',
|
|
249
|
+
description: 'Maximum number of observations to return (default: 168 for one week of hourly data)',
|
|
250
|
+
minimum: 1,
|
|
251
|
+
maximum: 500,
|
|
252
|
+
default: 168
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
required: ['latitude', 'longitude', 'start_date', 'end_date']
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
check_service_status: {
|
|
259
|
+
name: 'check_service_status',
|
|
260
|
+
description: 'Check the operational status of the NOAA and Open-Meteo weather APIs. Use this when experiencing errors or to proactively verify service availability before making weather data requests. Returns current status, helpful messages, and links to official status pages.',
|
|
261
|
+
inputSchema: {
|
|
262
|
+
type: 'object',
|
|
263
|
+
properties: {},
|
|
264
|
+
required: []
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
search_location: {
|
|
268
|
+
name: 'search_location',
|
|
269
|
+
description: 'Search for locations by name to get coordinates for weather queries. Uses Nominatim (OpenStreetMap) for excellent coverage of cities, towns, villages, and hamlets worldwide. Use this when the user provides a location name instead of coordinates (e.g., "Paris", "New York", "Tokyo", "San Francisco, CA", "Small Village, County"). Returns location matches with coordinates, timezone, elevation, and other metadata. Enables natural language location queries like "What\'s the weather in Paris?" by converting location names to coordinates.',
|
|
270
|
+
inputSchema: {
|
|
271
|
+
type: 'object',
|
|
272
|
+
properties: {
|
|
273
|
+
query: {
|
|
274
|
+
type: 'string',
|
|
275
|
+
description: 'Location name(pinyin for china) to search for (e.g., "Paris", "New York, NY", "Tokyo", "Beijing")'
|
|
276
|
+
},
|
|
277
|
+
limit: {
|
|
278
|
+
type: 'number',
|
|
279
|
+
description: 'Maximum number of results to return (1-100, default: 5)',
|
|
280
|
+
minimum: 1,
|
|
281
|
+
maximum: 100,
|
|
282
|
+
default: 5
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
required: ['query']
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
get_air_quality: {
|
|
289
|
+
name: 'get_air_quality',
|
|
290
|
+
description: 'Get air quality data including AQI (Air Quality Index), pollutant concentrations, and UV index for a location (global coverage). Use this when asked about "air quality", "pollution", "AQI", "UV index", "safe to exercise outside", or health-related environmental conditions. Returns current conditions and optional hourly forecast. Shows appropriate AQI scale (US AQI for US locations, European EAQI elsewhere) with health recommendations. Pollutants include PM2.5, PM10, ozone, NO2, SO2, and CO.',
|
|
291
|
+
inputSchema: {
|
|
292
|
+
type: 'object',
|
|
293
|
+
properties: {
|
|
294
|
+
latitude: {
|
|
295
|
+
type: 'number',
|
|
296
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
297
|
+
minimum: -90,
|
|
298
|
+
maximum: 90
|
|
299
|
+
},
|
|
300
|
+
longitude: {
|
|
301
|
+
type: 'number',
|
|
302
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
303
|
+
minimum: -180,
|
|
304
|
+
maximum: 180
|
|
305
|
+
},
|
|
306
|
+
forecast: {
|
|
307
|
+
type: 'boolean',
|
|
308
|
+
description: 'Include hourly air quality forecast for next 5 days (default: false, shows current only)',
|
|
309
|
+
default: false
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
required: ['latitude', 'longitude']
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
get_marine_conditions: {
|
|
316
|
+
name: 'get_marine_conditions',
|
|
317
|
+
description: 'Get marine conditions including wave height, swell, ocean currents, and sea state for a location (global coverage). Use this when asked about "ocean conditions", "wave height", "surf conditions", "safe to boat", "marine forecast", "swell", or "sea state". Returns current conditions and optional daily/hourly forecast. Includes significant wave height, wind waves, swell, wave period, and ocean currents. Shows safety assessment for maritime activities. NOTE: Data has limited accuracy in coastal areas and is NOT suitable for coastal navigation - always consult official marine forecasts.',
|
|
318
|
+
inputSchema: {
|
|
319
|
+
type: 'object',
|
|
320
|
+
properties: {
|
|
321
|
+
latitude: {
|
|
322
|
+
type: 'number',
|
|
323
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
324
|
+
minimum: -90,
|
|
325
|
+
maximum: 90
|
|
326
|
+
},
|
|
327
|
+
longitude: {
|
|
328
|
+
type: 'number',
|
|
329
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
330
|
+
minimum: -180,
|
|
331
|
+
maximum: 180
|
|
332
|
+
},
|
|
333
|
+
forecast: {
|
|
334
|
+
type: 'boolean',
|
|
335
|
+
description: 'Include marine forecast for next 5 days (default: false, shows current only)',
|
|
336
|
+
default: false
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
required: ['latitude', 'longitude']
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
get_weather_imagery: {
|
|
343
|
+
name: 'get_weather_imagery',
|
|
344
|
+
description: 'Get weather imagery including radar, satellite, and precipitation maps for a location (global coverage). Use this when asked about "show radar", "satellite image", "precipitation map", "weather map", "animated radar", or "what does radar show". Returns image URLs with timestamps for current or animated weather visualization. Supports precipitation radar (global via RainViewer). Includes disclaimer about data delays and official forecast consultation. For numerical forecast data, use get_forecast instead.',
|
|
345
|
+
inputSchema: {
|
|
346
|
+
type: 'object',
|
|
347
|
+
properties: {
|
|
348
|
+
latitude: {
|
|
349
|
+
type: 'number',
|
|
350
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
351
|
+
minimum: -90,
|
|
352
|
+
maximum: 90
|
|
353
|
+
},
|
|
354
|
+
longitude: {
|
|
355
|
+
type: 'number',
|
|
356
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
357
|
+
minimum: -180,
|
|
358
|
+
maximum: 180
|
|
359
|
+
},
|
|
360
|
+
type: {
|
|
361
|
+
type: 'string',
|
|
362
|
+
description: 'Type of imagery: "radar", "satellite", or "precipitation" (default: "precipitation")',
|
|
363
|
+
enum: ['radar', 'satellite', 'precipitation'],
|
|
364
|
+
default: 'precipitation'
|
|
365
|
+
},
|
|
366
|
+
animated: {
|
|
367
|
+
type: 'boolean',
|
|
368
|
+
description: 'Return animated frames showing progression over time (default: false)',
|
|
369
|
+
default: false
|
|
370
|
+
},
|
|
371
|
+
layers: {
|
|
372
|
+
type: 'array',
|
|
373
|
+
description: 'Optional layers to include in imagery (future enhancement)',
|
|
374
|
+
items: {
|
|
375
|
+
type: 'string'
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
required: ['latitude', 'longitude', 'type']
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
get_lightning_activity: {
|
|
383
|
+
name: 'get_lightning_activity',
|
|
384
|
+
description: 'Get real-time lightning strike activity and safety assessment for a location (global coverage). Use this when asked about "lightning nearby", "lightning strikes", "thunderstorm activity", "is it safe from lightning", or "lightning danger". Returns recent strikes within specified radius and time window, including distance, polarity, intensity, and critical safety recommendations. Provides 4-level safety assessment (safe/elevated/high/extreme) based on proximity. SAFETY-CRITICAL tool for outdoor activities and severe weather monitoring.',
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: 'object',
|
|
387
|
+
properties: {
|
|
388
|
+
latitude: {
|
|
389
|
+
type: 'number',
|
|
390
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
391
|
+
minimum: -90,
|
|
392
|
+
maximum: 90
|
|
393
|
+
},
|
|
394
|
+
longitude: {
|
|
395
|
+
type: 'number',
|
|
396
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
397
|
+
minimum: -180,
|
|
398
|
+
maximum: 180
|
|
399
|
+
},
|
|
400
|
+
radius: {
|
|
401
|
+
type: 'number',
|
|
402
|
+
description: 'Search radius in kilometers (1-500, default: 100)',
|
|
403
|
+
minimum: 1,
|
|
404
|
+
maximum: 500,
|
|
405
|
+
default: 100
|
|
406
|
+
},
|
|
407
|
+
timeWindow: {
|
|
408
|
+
type: 'number',
|
|
409
|
+
description: 'Time window in minutes for historical strikes (5-120, default: 60)',
|
|
410
|
+
minimum: 5,
|
|
411
|
+
maximum: 120,
|
|
412
|
+
default: 60
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
required: ['latitude', 'longitude']
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
get_river_conditions: {
|
|
419
|
+
name: 'get_river_conditions',
|
|
420
|
+
description: 'Monitor river levels and flood status for a location (US only). Use this when asked about "river flooding", "river level", "flood stage", "streamflow", "safe to kayak", or "river conditions". Returns current river gauge data within specified radius including river stage, flow rate, flood category levels (action/minor/moderate/major), and forecasted conditions. Provides safety assessment based on flood stages. SAFETY-CRITICAL tool for flood-prone areas and water recreation.',
|
|
421
|
+
inputSchema: {
|
|
422
|
+
type: 'object',
|
|
423
|
+
properties: {
|
|
424
|
+
latitude: {
|
|
425
|
+
type: 'number',
|
|
426
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
427
|
+
minimum: -90,
|
|
428
|
+
maximum: 90
|
|
429
|
+
},
|
|
430
|
+
longitude: {
|
|
431
|
+
type: 'number',
|
|
432
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
433
|
+
minimum: -180,
|
|
434
|
+
maximum: 180
|
|
435
|
+
},
|
|
436
|
+
radius: {
|
|
437
|
+
type: 'number',
|
|
438
|
+
description: 'Search radius in kilometers (1-500, default: 50)',
|
|
439
|
+
minimum: 1,
|
|
440
|
+
maximum: 500,
|
|
441
|
+
default: 50
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
required: ['latitude', 'longitude']
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
get_wildfire_info: {
|
|
448
|
+
name: 'get_wildfire_info',
|
|
449
|
+
description: 'Monitor active wildfires and fire perimeters for a location (US focus). Use this when asked about "wildfires nearby", "fire danger", "active fires", "wildfire smoke", "fire perimeters", or "evacuation risk". Returns active wildfire information within specified radius including fire name, size, containment percentage, distance from location, and safety assessment. Provides critical evacuation awareness and air quality impact information. SAFETY-CRITICAL tool for wildfire-prone areas.',
|
|
450
|
+
inputSchema: {
|
|
451
|
+
type: 'object',
|
|
452
|
+
properties: {
|
|
453
|
+
latitude: {
|
|
454
|
+
type: 'number',
|
|
455
|
+
description: 'Latitude of the location (-90 to 90)',
|
|
456
|
+
minimum: -90,
|
|
457
|
+
maximum: 90
|
|
458
|
+
},
|
|
459
|
+
longitude: {
|
|
460
|
+
type: 'number',
|
|
461
|
+
description: 'Longitude of the location (-180 to 180)',
|
|
462
|
+
minimum: -180,
|
|
463
|
+
maximum: 180
|
|
464
|
+
},
|
|
465
|
+
radius: {
|
|
466
|
+
type: 'number',
|
|
467
|
+
description: 'Search radius in kilometers (1-500, default: 100)',
|
|
468
|
+
minimum: 1,
|
|
469
|
+
maximum: 500,
|
|
470
|
+
default: 100
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
required: ['latitude', 'longitude']
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
save_location: {
|
|
477
|
+
name: 'save_location',
|
|
478
|
+
description: 'Save a location for easy reuse in weather queries. Use this when a user wants to save a frequently used location like "home", "work", "cabin", or "aunt lisa\'s house". Accepts either a location query (which will be geocoded automatically) or direct coordinates. Saved locations can be used with all weather tools by providing location_name instead of coordinates. Makes it easy to ask "What\'s the weather forecast at home?" without repeatedly providing coordinates. SMART UPDATES: If the alias already exists and you only provide name/activities (without location details), it will update just those fields while preserving coordinates.',
|
|
479
|
+
inputSchema: {
|
|
480
|
+
type: 'object',
|
|
481
|
+
properties: {
|
|
482
|
+
alias: {
|
|
483
|
+
type: 'string',
|
|
484
|
+
description: 'Short name/alias for this location (e.g., "home", "work", "cabin"). Will be lowercased automatically. Max 50 characters.',
|
|
485
|
+
maxLength: 50
|
|
486
|
+
},
|
|
487
|
+
location_query: {
|
|
488
|
+
type: 'string',
|
|
489
|
+
description: 'Location to geocode and save (e.g., "Seattle, WA", "Paris, France", "Lake Tahoe, CA"). Will be geocoded using Nominatim. Not required if latitude/longitude provided.'
|
|
490
|
+
},
|
|
491
|
+
latitude: {
|
|
492
|
+
type: 'number',
|
|
493
|
+
description: 'Latitude if providing coordinates directly. Not required if location_query provided.',
|
|
494
|
+
minimum: -90,
|
|
495
|
+
maximum: 90
|
|
496
|
+
},
|
|
497
|
+
longitude: {
|
|
498
|
+
type: 'number',
|
|
499
|
+
description: 'Longitude if providing coordinates directly. Not required if location_query provided.',
|
|
500
|
+
minimum: -180,
|
|
501
|
+
maximum: 180
|
|
502
|
+
},
|
|
503
|
+
name: {
|
|
504
|
+
type: 'string',
|
|
505
|
+
description: 'Display name for the location (required when using latitude/longitude). E.g., "My Home in Seattle"'
|
|
506
|
+
},
|
|
507
|
+
description: {
|
|
508
|
+
type: 'string',
|
|
509
|
+
description: 'Short description for natural language matching (e.g., "My sister\'s house", "The lake house"). Helps Claude understand contextual references.'
|
|
510
|
+
},
|
|
511
|
+
alternateNames: {
|
|
512
|
+
type: 'array',
|
|
513
|
+
description: 'Alternate names/aliases for this location (e.g., ["sister\'s place", "Jane\'s house"]). Enables more natural language queries.',
|
|
514
|
+
items: {
|
|
515
|
+
type: 'string'
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
notes: {
|
|
519
|
+
type: 'string',
|
|
520
|
+
description: 'Freeform notes about this location for future reference'
|
|
521
|
+
},
|
|
522
|
+
activities: {
|
|
523
|
+
type: 'array',
|
|
524
|
+
items: {
|
|
525
|
+
type: 'string'
|
|
526
|
+
},
|
|
527
|
+
description: 'Optional activities you do at this location (e.g., ["boating", "fishing"], ["hiking", "camping"]). Helps AI provide relevant weather information. Each activity max 50 characters.'
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
required: ['alias']
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
list_saved_locations: {
|
|
534
|
+
name: 'list_saved_locations',
|
|
535
|
+
description: 'List all saved locations. Use this when a user wants to see their saved locations or asks "what locations do I have saved?" or "show my saved places". Returns all saved locations with their aliases, names, coordinates, and other metadata. Helpful for reminding users what location names they can use with weather tools.',
|
|
536
|
+
inputSchema: {
|
|
537
|
+
type: 'object',
|
|
538
|
+
properties: {},
|
|
539
|
+
required: []
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
get_saved_location: {
|
|
543
|
+
name: 'get_saved_location',
|
|
544
|
+
description: 'Get details for a specific saved location. Use this when a user wants to view information about a particular saved location, like "show me details for my home location" or "what are the coordinates for my cabin?".',
|
|
545
|
+
inputSchema: {
|
|
546
|
+
type: 'object',
|
|
547
|
+
properties: {
|
|
548
|
+
alias: {
|
|
549
|
+
type: 'string',
|
|
550
|
+
description: 'The alias/name of the saved location to retrieve (e.g., "home", "work")'
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
required: ['alias']
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
remove_saved_location: {
|
|
557
|
+
name: 'remove_saved_location',
|
|
558
|
+
description: 'Remove a saved location. Use this when a user wants to delete a saved location, like "remove my work location" or "delete the cabin from saved locations".',
|
|
559
|
+
inputSchema: {
|
|
560
|
+
type: 'object',
|
|
561
|
+
properties: {
|
|
562
|
+
alias: {
|
|
563
|
+
type: 'string',
|
|
564
|
+
description: 'The alias/name of the saved location to remove (e.g., "home", "work")'
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
required: ['alias']
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
/**
|
|
572
|
+
* Handler for listing available tools
|
|
573
|
+
* Only returns tools that are enabled in the configuration
|
|
574
|
+
*/
|
|
575
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
576
|
+
const enabledTools = toolConfig.getEnabledTools();
|
|
577
|
+
const tools = enabledTools
|
|
578
|
+
.map(toolName => TOOL_DEFINITIONS[toolName])
|
|
579
|
+
.filter(Boolean); // Filter out any undefined tools
|
|
580
|
+
return { tools };
|
|
581
|
+
});
|
|
582
|
+
/**
|
|
583
|
+
* Handler for tool execution
|
|
584
|
+
* Validates that tools are enabled before execution
|
|
585
|
+
*/
|
|
586
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
587
|
+
const { name, arguments: args } = request.params;
|
|
588
|
+
try {
|
|
589
|
+
// Check if tool is enabled
|
|
590
|
+
if (!toolConfig.isEnabled(name)) {
|
|
591
|
+
throw new Error(`Tool '${name}' is not enabled. Please check your ENABLED_TOOLS configuration.`);
|
|
592
|
+
}
|
|
593
|
+
switch (name) {
|
|
594
|
+
case 'get_forecast':
|
|
595
|
+
return await withAnalytics('get_forecast', async () => handleGetForecast(args, noaaService, openMeteoService, locationStore, geocodingService, nceiService));
|
|
596
|
+
case 'get_alerts':
|
|
597
|
+
return await withAnalytics('get_alerts', async () => handleGetAlerts(args, noaaService));
|
|
598
|
+
case 'get_historical_weather':
|
|
599
|
+
return await withAnalytics('get_historical_weather', async () => handleGetHistoricalWeather(args, noaaService, openMeteoService));
|
|
600
|
+
case 'check_service_status':
|
|
601
|
+
return await withAnalytics('check_service_status', async () => handleCheckServiceStatus(noaaService, openMeteoService, SERVER_VERSION));
|
|
602
|
+
case 'search_location':
|
|
603
|
+
return await withAnalytics('search_location', async () => handleSearchLocation(args, geocodingService));
|
|
604
|
+
case 'get_air_quality':
|
|
605
|
+
return await withAnalytics('get_air_quality', async () => handleGetAirQuality(args, openMeteoService));
|
|
606
|
+
case 'get_marine_conditions':
|
|
607
|
+
return await withAnalytics('get_marine_conditions', async () => handleGetMarineConditions(args, noaaService, openMeteoService));
|
|
608
|
+
case 'get_weather_imagery':
|
|
609
|
+
return await withAnalytics('get_weather_imagery', async () => {
|
|
610
|
+
const result = await getWeatherImagery(args);
|
|
611
|
+
const formatted = formatWeatherImageryResponse(result);
|
|
612
|
+
return {
|
|
613
|
+
content: [
|
|
614
|
+
{
|
|
615
|
+
type: 'text',
|
|
616
|
+
text: formatted
|
|
617
|
+
}
|
|
618
|
+
]
|
|
619
|
+
};
|
|
620
|
+
});
|
|
621
|
+
case 'get_lightning_activity':
|
|
622
|
+
return await withAnalytics('get_lightning_activity', async () => {
|
|
623
|
+
const result = await getLightningActivity(args);
|
|
624
|
+
const formatted = formatLightningActivityResponse(result);
|
|
625
|
+
return {
|
|
626
|
+
content: [
|
|
627
|
+
{
|
|
628
|
+
type: 'text',
|
|
629
|
+
text: formatted
|
|
630
|
+
}
|
|
631
|
+
]
|
|
632
|
+
};
|
|
633
|
+
});
|
|
634
|
+
case 'get_river_conditions':
|
|
635
|
+
return await withAnalytics('get_river_conditions', async () => handleGetRiverConditions(args, noaaService));
|
|
636
|
+
case 'get_wildfire_info':
|
|
637
|
+
return await withAnalytics('get_wildfire_info', async () => handleGetWildfireInfo(args, nifcService));
|
|
638
|
+
case 'save_location':
|
|
639
|
+
return await withAnalytics('save_location', async () => handleSaveLocation(args, locationStore, nominatimService));
|
|
640
|
+
case 'list_saved_locations':
|
|
641
|
+
return await withAnalytics('list_saved_locations', async () => handleListSavedLocations(locationStore));
|
|
642
|
+
case 'get_saved_location':
|
|
643
|
+
return await withAnalytics('get_saved_location', async () => handleGetSavedLocation(args, locationStore));
|
|
644
|
+
case 'remove_saved_location':
|
|
645
|
+
return await withAnalytics('remove_saved_location', async () => handleRemoveSavedLocation(args, locationStore));
|
|
646
|
+
default:
|
|
647
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
catch (error) {
|
|
651
|
+
// Redact sensitive fields from args before logging
|
|
652
|
+
const redactedArgs = args ? redactSensitiveFields(args) : undefined;
|
|
653
|
+
// Log the error with redacted details
|
|
654
|
+
logger.error('Tool execution error', error, {
|
|
655
|
+
tool: name,
|
|
656
|
+
args: redactedArgs ? JSON.stringify(redactedArgs) : undefined,
|
|
657
|
+
});
|
|
658
|
+
// Format error for user display (sanitized)
|
|
659
|
+
const userMessage = formatErrorForUser(error);
|
|
660
|
+
return {
|
|
661
|
+
content: [
|
|
662
|
+
{
|
|
663
|
+
type: 'text',
|
|
664
|
+
text: userMessage
|
|
665
|
+
}
|
|
666
|
+
],
|
|
667
|
+
isError: true
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
/**
|
|
672
|
+
* Start the server
|
|
673
|
+
*/
|
|
674
|
+
async function main() {
|
|
675
|
+
const transport = new StdioServerTransport();
|
|
676
|
+
// Set up graceful shutdown handlers
|
|
677
|
+
const shutdown = async (signal) => {
|
|
678
|
+
logger.info(`Received ${signal}, shutting down gracefully...`);
|
|
679
|
+
try {
|
|
680
|
+
// 1. Flush analytics first (fast)
|
|
681
|
+
await analytics.shutdown();
|
|
682
|
+
logger.info('Analytics flushed');
|
|
683
|
+
// 2. Clean up resources
|
|
684
|
+
noaaService.clearCache();
|
|
685
|
+
openMeteoService.clearCache();
|
|
686
|
+
logger.info('Cache cleared');
|
|
687
|
+
// 3. Close server connection
|
|
688
|
+
await server.close();
|
|
689
|
+
logger.info('Server closed');
|
|
690
|
+
process.exit(0);
|
|
691
|
+
}
|
|
692
|
+
catch (error) {
|
|
693
|
+
logger.error('Error during shutdown', error);
|
|
694
|
+
process.exit(1);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
698
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
699
|
+
try {
|
|
700
|
+
await server.connect(transport);
|
|
701
|
+
logger.info('Weather MCP Server started', {
|
|
702
|
+
version: SERVER_VERSION,
|
|
703
|
+
cacheEnabled: CacheConfig.enabled,
|
|
704
|
+
logLevel: process.env.LOG_LEVEL || 'INFO',
|
|
705
|
+
enabledTools: toolConfig.getEnabledTools().length,
|
|
706
|
+
toolList: toolConfig.getEnabledTools().join(', ')
|
|
707
|
+
});
|
|
708
|
+
// Inform users about version and upgrade options
|
|
709
|
+
logger.info('Version check', {
|
|
710
|
+
installedVersion: SERVER_VERSION,
|
|
711
|
+
latestRelease: 'https://github.com/weather-mcp/weather-mcp/releases/latest',
|
|
712
|
+
upgradeInstructions: 'https://github.com/weather-mcp/weather-mcp#upgrading-to-latest-version',
|
|
713
|
+
autoUpdateTip: 'Use npx -y @dangahagan/weather-mcp@latest in MCP config for automatic updates'
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
catch (error) {
|
|
717
|
+
logger.error('Failed to start server', error);
|
|
718
|
+
throw error;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
main().catch((error) => {
|
|
722
|
+
logger.error('Fatal error in main()', error);
|
|
723
|
+
// Log structured error for monitoring
|
|
724
|
+
console.error(JSON.stringify({
|
|
725
|
+
timestamp: new Date().toISOString(),
|
|
726
|
+
level: 'FATAL',
|
|
727
|
+
message: 'Application failed to start',
|
|
728
|
+
error: {
|
|
729
|
+
message: error instanceof Error ? error.message : String(error),
|
|
730
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
731
|
+
}
|
|
732
|
+
}));
|
|
733
|
+
process.exit(1);
|
|
734
|
+
});
|
|
735
|
+
//# sourceMappingURL=index.js.map
|