Skip to main content
Glama
WeatherDailyTool.ts5.21 kB
import { z } from "zod"; import axios from "axios"; import type { TextContent } from "@modelcontextprotocol/sdk/types.js"; import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js"; // Zod schemas for validation export const inputShape = { location: z.string().min(1, "Location must be at least 1 character"), days: z.number().int().min(1).max(15).default(5).optional().describe("Number of days for forecast (1-15)"), units: z.enum(["imperial", "metric"]).default("metric").optional().describe("Temperature unit system") }; export const inputSchema = z.object(inputShape).describe("Get daily weather forecast"); // JSON schema for tool registration (OpenAI-compatible) export const inputJsonSchema = { type: "object", description: "Parameters for the daily weather-forecast tool", properties: { location: { type: "string", description: "The location to fetch the daily forecast for", }, days: { type: "number", description: "Number of days to forecast (1, 5, 10, or 15). Default is 5.", enum: [1, 5, 10, 15] }, units: { type: "string", description: "Temperature unit system (metric for Celsius, imperial for Fahrenheit). Default is metric.", enum: ["metric", "imperial"] } }, required: ["location"], additionalProperties: false, }; // Handler function for daily forecast export async function handler( args: { [x: string]: any }, extra: RequestHandlerExtra<any, any> ): Promise<{ content: TextContent[] }> { // Validate args using the Zod schema let validatedArgs: z.infer<typeof inputSchema>; try { validatedArgs = inputSchema.parse(args); } catch (error) { if (error instanceof z.ZodError) { const errorMessages = error.errors .map((e) => `${e.path.join('.')}: ${e.message}`) .join(', '); return { content: [{ type: 'text', text: `Invalid input: ${errorMessages}` }] }; } return { content: [{ type: 'text', text: 'An unexpected error occurred during input validation.' }] }; } const { location, days = 5, units = "metric" } = validatedArgs; const apiKey = process.env.ACCUWEATHER_API_KEY; if (!apiKey) { return { content: [{ type: 'text', text: 'Error: AccuWeather API key not configured' }] }; } try { // Step 1: Get location key const locationUrl = `https://dataservice.accuweather.com/locations/v1/cities/search?apikey=${apiKey}&q=${encodeURIComponent(location)}`; const locationResp = await axios.get(locationUrl); if (!locationResp.data || locationResp.data.length === 0) { return { content: [{ type: 'text', text: `No location found for: ${location}` }] }; } const locationKey = locationResp.data[0].Key; // Get valid forecast period (AccuWeather supports 1, 5, 10, or 15 days) let forecastDays = 5; // default if (days === 1) forecastDays = 1; else if (days <= 5) forecastDays = 5; else if (days <= 10) forecastDays = 10; else forecastDays = 15; // Step 2: Get forecast with location key const forecastUrl = `https://dataservice.accuweather.com/forecasts/v1/daily/${forecastDays}day/${locationKey}?apikey=${apiKey}&metric=${units === "metric" ? "true" : "false"}`; const forecastResp = await axios.get(forecastUrl); const data = forecastResp.data; if (!data || !data.DailyForecasts || !Array.isArray(data.DailyForecasts) || data.DailyForecasts.length === 0) { return { content: [{ type: 'text', text: `No daily forecast data available for location: ${location}` }] }; } const degreeSymbol = "°"; const unitSymbol = units === "metric" ? "C" : "F"; const content: TextContent[] = data.DailyForecasts.map((day: any) => { const date = new Date(day.Date); const formattedDate = date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric' }); return { type: 'text', text: `${formattedDate}: ${day.Temperature.Minimum.Value}${degreeSymbol}${unitSymbol} to ${day.Temperature.Maximum.Value}${degreeSymbol}${unitSymbol}, Day: ${day.Day.IconPhrase}, Night: ${day.Night.IconPhrase}${day.Day.HasPrecipitation || day.Night.HasPrecipitation ? ' (Precipitation expected)' : ''}` }; }); return { content }; } catch (error) { console.error("WeatherDailyTool handler error:", error); let errorMessage = "An error occurred while fetching weather data."; if (axios.isAxiosError(error)) { if (error.response?.status === 401) { errorMessage = "Invalid AccuWeather API key. Please check your credentials."; } else if (error.response?.status === 404) { errorMessage = `Location not found: ${location}`; } else if (error.response) { errorMessage = `AccuWeather API error (${error.response.status}): ${error.response.data?.Message || error.message}`; } else if (error.request) { errorMessage = "Network error: Unable to connect to AccuWeather API."; } } return { content: [{ type: 'text', text: errorMessage }] }; } } export default { inputShape, inputSchema, inputJsonSchema, handler };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TimLukaHorstmann/mcp-weather'

If you have feedback or need assistance with the MCP directory API, please join our Discord server