UNPKG

@trashwbin/weather-service

Version:

A weather service that provides weather alerts and forecasts using the National Weather Service API

167 lines 5.99 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; /** * @Author Abin * @Description 天气服务类,提供天气预报和警报功能 */ export class WeatherService { static NWS_API_BASE = "https://api.weather.gov"; static USER_AGENT = "weather-app/1.0"; server; constructor() { this.server = new McpServer({ name: "weather", version: "1.0.0", capabilities: { resources: {}, tools: {}, }, }); this.registerTools(); } /** * 发起 NWS API 请求 * @param url API 请求地址 * @returns 请求结果 */ async makeNWSRequest(url) { const headers = { "User-Agent": WeatherService.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()); } catch (error) { console.error("Error making NWS request:", error); return null; } } /** * 格式化警报数据 * @param feature 警报特征数据 * @returns 格式化后的警报文本 */ formatAlert(feature) { 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"); } /** * 注册天气工具 */ registerTools() { this.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 alerts = await this.getAlerts(state); return { content: [ { type: "text", text: alerts, }, ], }; }); this.server.tool("get_forecast", "Get weather forecast for a location", { latitude: z.number().min(-90).max(90).describe("Latitude of the location"), longitude: z .number() .min(-180) .max(180) .describe("Longitude of the location"), }, async ({ latitude, longitude }) => { const forecast = await this.getForecast(latitude, longitude); return { content: [ { type: "text", text: forecast, }, ], }; }); } /** * 获取指定州的天气警报 * @param state 两字母的州代码 * @returns 警报信息文本 */ async getAlerts(state) { const stateCode = state.toUpperCase(); const alertsUrl = `${WeatherService.NWS_API_BASE}/alerts?area=${stateCode}`; const alertsData = await this.makeNWSRequest(alertsUrl); if (!alertsData) { return "Failed to retrieve alerts data"; } const features = alertsData.features || []; if (features.length === 0) { return `No active alerts for ${stateCode}`; } const formattedAlerts = features.map((feature) => this.formatAlert(feature)); return `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`; } /** * 获取指定位置的天气预报 * @param latitude 纬度 * @param longitude 经度 * @returns 天气预报文本 */ async getForecast(latitude, longitude) { const pointsUrl = `${WeatherService.NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`; const pointsData = await this.makeNWSRequest(pointsUrl); if (!pointsData) { return `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`; } const forecastUrl = pointsData.properties?.forecast; if (!forecastUrl) { return "Failed to get forecast URL from grid point data"; } const forecastData = await this.makeNWSRequest(forecastUrl); if (!forecastData) { return "Failed to retrieve forecast data"; } const periods = forecastData.properties?.periods || []; if (periods.length === 0) { return "No forecast periods available"; } const formattedForecast = periods.map((period) => [ `${period.name || "Unknown"}:`, `Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`, `Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`, `${period.shortForecast || "No forecast available"}`, "---", ].join("\n")); return `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`; } /** * 启动天气服务 */ async start() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error("Weather MCP Server running on stdio"); } } // 如果作为命令行工具运行 if (import.meta.url === new URL(import.meta.url).href) { const weatherService = new WeatherService(); weatherService.start().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); }); } //# sourceMappingURL=index.js.map