Skip to main content
Glama
index.ts5.59 kB
// Import MCP server framework import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // zod for input validation import { z } from "zod"; // Base URL for the US National Weather Service API const NWS_API_BASE = "https://api.weather.gov"; // Custom User-Agent required by NWS API const USER_AGENT = "weather-app/1.0"; // Create an MCP server instance with basic metadata (NEW API – no capabilities) const server = new McpServer({ name: "weather", version: "1.0.0", }); // --------------------------------------------- // Helper: General fetch wrapper for NWS API // --------------------------------------------- async function makeNWSRequest<T>(url: string): Promise<T | null> { const headers = { "User-Agent": USER_AGENT, Accept: "application/geo+json", }; try { const response = await fetch(url, { headers }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return (await response.json()) as T; } catch (error) { console.error("Error making NWS request:", error); return null; } } // --------------------------------------------- // Types for API responses // --------------------------------------------- interface AlertFeature { properties: { event?: string; areaDesc?: string; severity?: string; status?: string; headline?: string; }; } interface ForecastPeriod { name?: string; temperature?: number; temperatureUnit?: string; windSpeed?: string; windDirection?: string; shortForecast?: string; } interface AlertsResponse { features: AlertFeature[]; } interface PointsResponse { properties: { forecast?: string; }; } interface ForecastResponse { properties: { periods: ForecastPeriod[]; }; } // --------------------------------------------- // Helper: Format alert into readable text // --------------------------------------------- function formatAlert(feature: AlertFeature): string { const props = feature.properties; return [ `Event: ${props.event || "Unknown"}`, `Area: ${props.areaDesc || "Unknown"}`, `Severity: ${props.severity || "Unknown"}`, `Status: ${props.status || "Unknown"}`, `Headline: ${props.headline || "No headline"}`, "---", ].join("\n"); } // --------------------------------------------- // TOOL #1 — GET WEATHER ALERTS FOR A STATE // --------------------------------------------- server.tool( "get_alerts", "Get weather alerts for a state", { state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"), }, async ({ state }) => { const stateCode = state.toUpperCase(); const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`; const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl); if (!alertsData) { return { content: [{ type: "text", text: "Failed to retrieve alerts data" }], }; } const features = alertsData.features || []; if (features.length === 0) { return { content: [{ type: "text", text: `No active alerts for ${stateCode}` }], }; } const text = `Active alerts for ${stateCode}:\n\n${features .map(formatAlert) .join("\n")}`; return { content: [{ type: "text", text }] }; } ); // --------------------------------------------- // TOOL #2 — GET WEATHER FORECAST FOR COORDINATES // --------------------------------------------- server.tool( "get_forecast", "Get weather forecast for a location", { latitude: z.number().min(-90).max(90).describe("Latitude"), longitude: z.number().min(-180).max(180).describe("Longitude"), }, async ({ latitude, longitude }) => { const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed( 4 )},${longitude.toFixed(4)}`; const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl); if (!pointsData) { return { content: [ { type: "text", text: `Failed to retrieve grid point data for ${latitude}, ${longitude}. Only US locations are supported.`, }, ], }; } const forecastUrl = pointsData.properties?.forecast; if (!forecastUrl) { return { content: [{ type: "text", text: "No forecast URL found for location" }], }; } const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl); if (!forecastData) { return { content: [{ type: "text", text: "Failed to retrieve forecast" }] }; } const periods = forecastData.properties?.periods || []; if (periods.length === 0) { return { content: [{ type: "text", text: "No forecast periods available" }] }; } const text = `Forecast for ${latitude}, ${longitude}:\n\n${periods .map((p) => [ `${p.name}:`, `Temperature: ${p.temperature}°${p.temperatureUnit}`, `Wind: ${p.windSpeed} ${p.windDirection}`, `${p.shortForecast}`, "---", ].join("\n") ) .join("\n")}`; return { content: [{ type: "text", text }] }; } ); // --------------------------------------------- // MAIN ENTRYPOINT — Start MCP Server // --------------------------------------------- async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Weather MCP Server running on stdio"); } // Start and handle fatal errors main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });

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/Sunil-paudel/mcpserverasof2025updated'

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