get-hourly-forecast
Retrieve hourly weather forecasts for up to 48 hours using city names or coordinates. Specify units (Celsius, Fahrenheit, Kelvin) and desired forecast duration for precise planning.
Instructions
Get hourly weather forecast for up to 48 hours
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | Number of hours to forecast (1-48, default: 48) | |
| location | Yes | City name (e.g., 'New York') or coordinates (e.g., 'lat,lon') | |
| units | No | Temperature units: metric (Celsius), imperial (Fahrenheit), or standard (Kelvin) |
Implementation Reference
- src/main.ts:216-275 (handler)Primary handler and registration: defines the tool with name, description, input schema, and execute function that orchestrates client resolution, location config, API call to getHourlyForecast, formatting, and error handling.server.addTool({ name: "get-hourly-forecast", description: "Get hourly weather forecast for up to 48 hours", parameters: getHourlyForecastSchema, execute: async (args, { session, log }) => { try { log.info("Getting hourly weather forecast", { location: args.location, hours: args.hours }); // Get OpenWeather client const client = getOpenWeatherClient(session as SessionData | undefined); // Configure client for this request configureClientForLocation(client, args.location, args.units); // Fetch hourly forecast data const requestedHours = args.hours || 48; const hourlyData = await client.getHourlyForecast(requestedHours); log.info("Successfully retrieved hourly weather forecast", { location: args.location, entries: hourlyData.length }); // Format the response const formattedForecast = formatHourlyForecast( hourlyData, `${hourlyData[0]?.lat?.toFixed(4)}, ${hourlyData[0]?.lon?.toFixed(4)}` || args.location, args.units ); return { content: [ { type: "text", text: formattedForecast } ] }; } catch (error) { log.error("Failed to get hourly weather forecast", { error: error instanceof Error ? error.message : 'Unknown error' }); // Provide helpful error messages if (error instanceof Error) { if (error.message.includes('city not found')) { throw new Error(`Location "${args.location}" not found. Please check the spelling or try using coordinates.`); } if (error.message.includes('Invalid API key')) { throw new Error('Invalid OpenWeatherMap API key. Please check your configuration.'); } } throw new Error(`Failed to get hourly weather forecast: ${error instanceof Error ? error.message : 'Unknown error'}`); } } });
- src/schemas.ts:29-33 (schema)Input schema using Zod: requires location string, optional units (metric/imperial/standard), optional hours (1-48).export const getHourlyForecastSchema = z.object({ location: z.string().describe("City name (e.g., 'New York') or coordinates (e.g., 'lat,lon')"), units: unitsSchema, hours: z.number().min(1).max(48).optional().describe("Number of hours to forecast (1-48, default: 48)"), });
- Supporting helper: formats raw hourly forecast data into a structured JSON object with formatted temperature, wind, visibility, etc., for the tool response.export function formatHourlyForecast(hourlyData: any[], location: string, units: Units = "metric"): string { const forecastData = { location, hourly_forecast: hourlyData.map((hour, index) => ({ hour: index + 1, datetime: formatDateTime(hour.dtRaw || hour.dt), temperature: { current: Math.round(hour.weather?.temp?.cur || hour.temp), feels_like: Math.round(hour.weather?.feelsLike?.cur || hour.feels_like), units: getTemperatureUnit(units) }, conditions: hour.weather?.description || hour.description, humidity: hour.weather?.humidity || hour.humidity, wind: { speed: Number((hour.weather?.wind?.speed || hour.wind_speed || 0).toFixed(1)), direction: getWindDirection(hour.weather?.wind?.deg || hour.wind_deg || 0), units: units === "imperial" ? "mph" : "m/s" }, pressure: hour.weather?.pressure || hour.pressure, visibility: (hour.weather?.visibility || hour.visibility) ? { value: units === "imperial" ? Number(((hour.weather?.visibility || hour.visibility) / 1609.34).toFixed(1)) : Number(((hour.weather?.visibility || hour.visibility) / 1000).toFixed(1)), units: units === "imperial" ? "mi" : "km" } : null, uvi: hour.weather?.uvi, clouds: hour.weather?.clouds, pop: hour.weather?.pop ? Math.round(hour.weather.pop * 100) : null, timestamp: hour.dtRaw || hour.dt })) }; return JSON.stringify(forecastData); }