Skip to main content
Glama

Weather MCP Server

by gmailhasan
index.js5.99 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { z } from "zod"; import express from "express"; import { randomUUID } from "crypto"; // Weather API endpoint const WEATHER_API = "https://api.open-meteo.com/v1/forecast"; // Define the input schema for our weather tool const WeatherInputSchema = z.object({ latitude: z.number().describe("Latitude coordinate"), longitude: z.number().describe("Longitude coordinate"), }); // Create the MCP server instance const server = new McpServer({ name: "weather-server", version: "1.0.0", capabilities: { tools: {}, }, }); // Helper function to fetch weather data async function fetchWeatherData(latitude, longitude) { const params = new URLSearchParams({ latitude: latitude.toString(), longitude: longitude.toString(), current: "temperature_2m,wind_speed_10m", hourly: "temperature_2m,relative_humidity_2m,wind_speed_10m", }); const url = `${WEATHER_API}?${params.toString()}`; try { const response = await fetch(url); if (!response.ok) { throw new Error(`Weather API returned status ${response.status}`); } return await response.json(); } catch (error) { throw new Error(`Failed to fetch weather data: ${error instanceof Error ? error.message : String(error)}`); } } // Register the get_weather tool server.registerTool("get_weather", { title: "Get Weather Data", description: "Fetches current weather and hourly forecast from Open-Meteo API for given coordinates", inputSchema: { latitude: z .number() .describe("Latitude coordinate (e.g., 52.52 for Berlin)"), longitude: z .number() .describe("Longitude coordinate (e.g., 13.41 for Berlin)"), }, }, async ({ latitude, longitude }) => { try { const weatherData = await fetchWeatherData(latitude, longitude); // Format the response const current = weatherData.current || {}; const hourly = weatherData.hourly || {}; let responseText = `Weather data for coordinates (${latitude}, ${longitude}):\n\n`; responseText += `Current conditions:\n`; responseText += `- Temperature: ${current.temperature_2m}°C\n`; responseText += `- Wind Speed: ${current.wind_speed_10m} km/h\n\n`; responseText += `Hourly forecast available for:\n`; responseText += `- Temperature (${hourly.temperature_2m?.length || 0} hours)\n`; responseText += `- Relative Humidity (${hourly.relative_humidity_2m?.length || 0} hours)\n`; responseText += `- Wind Speed (${hourly.wind_speed_10m?.length || 0} hours)\n`; // Include raw data for reference responseText += `\nRaw API Response:\n${JSON.stringify(weatherData, null, 2)}`; return { content: [ { type: "text", text: responseText, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error fetching weather data: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); // HTTP Server setup const app = express(); const PORT = process.env.PORT || 3000; app.use(express.json()); // Store active transports by session ID const transports = new Map(); // Health check endpoint app.get("/health", (_req, res) => { res.json({ status: "ok", server: "weather-mcp-server" }); }); // Main MCP endpoint app.post("/mcp", async (req, res) => { const sessionId = req.headers["mcp-session-id"]; let transport; if (sessionId && transports.has(sessionId)) { // Use existing transport for this session transport = transports.get(sessionId); } else { // Create new transport for new session transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (newSessionId) => { transports.set(newSessionId, transport); console.log(`New session initialized: ${newSessionId}`); }, }); transport.onclose = () => { if (transport.sessionId) { transports.delete(transport.sessionId); console.log(`Session closed: ${transport.sessionId}`); } }; await server.connect(transport); } await transport.handleRequest(req, res, req.body); }); // GET endpoint for SSE (Server-Sent Events) app.get("/mcp", async (req, res) => { const sessionId = req.headers["mcp-session-id"]; if (!sessionId || !transports.has(sessionId)) { res.status(400).json({ error: "Invalid or missing session ID" }); return; } const transport = transports.get(sessionId); await transport.handleRequest(req, res); }); // DELETE endpoint to close sessions app.delete("/mcp", async (req, res) => { const sessionId = req.headers["mcp-session-id"]; if (!sessionId || !transports.has(sessionId)) { res.status(400).json({ error: "Invalid or missing session ID" }); return; } const transport = transports.get(sessionId); await transport.handleRequest(req, res); }); // Start the HTTP server async function main() { app.listen(PORT, () => { console.log(`\n🌤️ Weather MCP Server running on HTTP`); console.log(`📡 Endpoint: http://localhost:${PORT}/mcp`); console.log(`🏥 Health check: http://localhost:${PORT}/health`); console.log(`\nPress Ctrl+C to stop the server\n`); }); } 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/gmailhasan/mcpexample'

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