nasa_power
Access global meteorological data for energy resource assessment. Analyze weather parameters by specifying location, date range, and community type (RE, SB, AG). Retrieve data in JSON or CSV format for informed energy planning.
Instructions
Prediction of Worldwide Energy Resources - meteorological data
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| community | Yes | User community (RE, SB, AG, etc.) | |
| end | Yes | End date (YYYYMMDD) | |
| format | No | Response format (json, csv, etc.) | |
| latitude | Yes | Latitude coordinate | |
| longitude | Yes | Longitude coordinate | |
| parameters | Yes | Comma-separated data parameters | |
| start | Yes | Start date (YYYYMMDD) |
Implementation Reference
- src/handlers/nasa/power.ts:120-222 (handler)Main execution logic for the nasa_power tool: validates parameters, calls NASA POWER API, formats response, adds as resource, and returns formatted text.export async function nasaPowerHandler(params: PowerParams) { try { // POWER API base URL const POWER_API_URL = 'https://power.larc.nasa.gov/api/temporal/daily/point'; // Validate and normalize parameters using the schema const validatedParams = powerParamsSchema.parse(params); // Call the NASA POWER API const response = await axios({ url: POWER_API_URL, params: validatedParams, // Use validated & normalized params method: 'GET', timeout: 30000 // Increased timeout to 30 seconds }); // Create a resource ID based on key parameters const resourceParams = []; if (validatedParams.parameters) resourceParams.push(`parameters=${validatedParams.parameters}`); if (validatedParams.latitude !== undefined) resourceParams.push(`lat=${validatedParams.latitude}`); if (validatedParams.longitude !== undefined) resourceParams.push(`lon=${validatedParams.longitude}`); if (validatedParams.start) resourceParams.push(`start=${validatedParams.start}`); if (validatedParams.end) resourceParams.push(`end=${validatedParams.end}`); const resourceId = `nasa://power/${validatedParams.community}?${resourceParams.join('&')}`; // Register the response as a resource addResource(resourceId, { name: `NASA POWER ${validatedParams.community.toUpperCase()} Data${validatedParams.latitude !== undefined ? ` at (${validatedParams.latitude}, ${validatedParams.longitude})` : ''}`, mimeType: validatedParams.format === 'json' ? 'application/json' : 'text/plain', text: validatedParams.format === 'json' ? JSON.stringify(response.data, null, 2) : response.data }); // Format the data for display const formattedText = formatPowerDataText(response.data, validatedParams); // Return the formatted result return { content: [ { type: "text", text: formattedText } ], isError: false }; } catch (error: any) { // Handle Zod validation errors separately if (error instanceof z.ZodError) { console.error('Error validating POWER parameters:', error.errors); return { isError: true, content: [{ type: "text", text: `Error: Invalid parameters for NASA POWER API. Issues: ${error.errors.map(e => `${e.path.join('.')} - ${e.message}`).join('; ')}` }] }; } console.error('Error in POWER handler:', error); let errorMessage = 'An unexpected error occurred'; if (error.response) { // The request was made and the server responded with an error status console.error('Response status:', error.response.status); console.error('Response headers:', JSON.stringify(error.response.headers)); console.error('Response data:', JSON.stringify(error.response.data).substring(0, 200)); // Check content type before assuming JSON for error response const contentType = error.response.headers?.['content-type'] || ''; let errorDetails = 'Unknown error'; if (contentType.includes('application/json') && error.response.data) { errorDetails = error.response.data?.message || error.response.data?.errors?.join(', ') || JSON.stringify(error.response.data).substring(0, 100); } else if (typeof error.response.data === 'string') { errorDetails = error.response.data.substring(0, 150); // Show raw text if not JSON } errorMessage = `NASA POWER API error (${error.response.status}): ${errorDetails}`; } else if (error.request) { // The request was made but no response was received console.error('Request details:'); console.error('- URL:', error.config?.url || 'Not available'); // Use config for URL console.error('- Params:', error.config?.params || 'Not available'); console.error('- Method:', error.request.method || 'Not available'); console.error('- Headers:', error.request._header || 'Not available'); errorMessage = `NASA POWER API network error: No response received or request timed out. Check network connectivity and API status. URL: ${error.config?.url}`; } else { // Something happened in setting up the request errorMessage = `NASA POWER API request setup error: ${error.message}`; } return { isError: true, content: [{ type: "text", text: `Error: ${errorMessage}` }] }; } }
- src/handlers/nasa/power.ts:6-22 (schema)Zod schema for validating input parameters to the nasa_power tool.export const powerParamsSchema = z.object({ parameters: z.string(), community: z.enum(['re', 'sb', 'ag', 'RE', 'SB', 'AG']).transform(val => val.toLowerCase()), format: z.enum(['json', 'csv', 'ascii', 'netcdf']).optional().default('json'), // Location parameters latitude: z.number().min(-90).max(90).optional(), longitude: z.number().min(-180).max(180).optional(), // Regional parameters (alternative to lat/long) bbox: z.string().optional(), // Temporal parameters start: z.string().optional(), end: z.string().optional(), // Climatology parameters climatology_start: z.string().optional(), climatology_end: z.string().optional(), time_standard: z.enum(['utc', 'lst']).optional().default('utc') });
- src/index.ts:1659-1674 (registration)Registers the MCP server request handler for method 'nasa/power', which invokes the dynamic handleToolCall dispatching to the power handler.z.object({ method: z.literal("nasa/power"), params: z.object({ community: z.string(), parameters: z.union([z.string(), z.array(z.string())]), latitude: z.number(), longitude: z.number(), start: z.string(), end: z.string(), format: z.string().optional() }).optional() }), async (request) => { return await handleToolCall("nasa/power", request.params || {}); } );
- src/index.ts:497-550 (registration)Lists 'nasa_power' tool in the tools/manifest response.{ name: "nasa_power", id: "nasa/power", description: "Prediction of Worldwide Energy Resources" }, { name: "jpl_sbdb", id: "jpl/sbdb", description: "Small-Body DataBase (SBDB) - primarily orbital data on all known asteroids and comets" }, { name: "jpl_fireball", id: "jpl/fireball", description: "Fireball atmospheric impact data reported by US Government sensors" }, { name: "jpl_jd_cal", id: "jpl/jd_cal", description: "Julian Day number to/from calendar date/time converter" }, { name: "jpl_nhats", id: "jpl/nhats", description: "Human-accessible NEOs (Near-Earth Objects) data" }, { name: "jpl_cad", id: "jpl/cad", description: "Asteroid and comet close approaches to the planets in the past and future" }, { name: "jpl_sentry", id: "jpl/sentry", description: "JPL Sentry - NEO Earth impact risk assessment data" }, { name: "jpl_horizons", id: "jpl/horizons", description: "JPL Horizons - Solar system objects ephemeris data" }, { name: "jpl_scout", id: "jpl/scout", description: "NEOCP orbits, ephemerides, and impact risk data (Scout)" }, // { // name: "nasa_earth", // id: "nasa/earth", // description: "Earth - Landsat satellite imagery and data" // } ] }; } );
- src/handlers/nasa/power.ts:29-114 (helper)Helper function to format the raw POWER API JSON response into a readable markdown summary with tables.function formatPowerDataText(responseData: any, params: PowerParams): string { try { const properties = responseData.properties || {}; const parameterData = properties.parameter || {}; const geometry = responseData.geometry || {}; const header = responseData.header || {}; const requestedParams = params.parameters.split(','); let locationStr = 'Global'; if (geometry.type === 'Point' && geometry.coordinates) { locationStr = `Point (${geometry.coordinates[1]}, ${geometry.coordinates[0]})`; } else if (params.bbox) { locationStr = `Region (${params.bbox})`; } let dateRangeStr = ''; if (header.start && header.end) { dateRangeStr = `${header.start} to ${header.end}`; } else if (params.start && params.end) { dateRangeStr = `${params.start} to ${params.end}`; } let text = `# NASA POWER Data\n\n`; text += `**Community:** ${params.community.toUpperCase()}\n`; text += `**Location:** ${locationStr}\n`; text += `**Date Range:** ${dateRangeStr || 'N/A'}\n\n`; text += `## Parameters\n\n`; requestedParams.forEach(paramKey => { const data = parameterData[paramKey]; const unit = header.parameter_information?.[paramKey]?.units || 'N/A'; const longName = header.parameter_information?.[paramKey]?.long_name || paramKey; text += `### ${longName} (${paramKey})\n`; text += `- **Units:** ${unit}\n`; if (data && typeof data === 'object') { const dates = Object.keys(data).sort(); if (dates.length > 0) { text += `- **Data:**\n`; text += '| Date | Value |\n'; text += '|------------|-------|\n'; // Show first 10 and last 10 dates to avoid excessive length const maxEntries = 10; const totalEntries = dates.length; let entriesShown = 0; for (let i = 0; i < Math.min(maxEntries, totalEntries); i++) { const date = dates[i]; const value = data[date] !== undefined ? data[date] : 'N/A'; text += `| ${date} | ${value} | `; entriesShown++; } if (totalEntries > maxEntries * 2) { text += `| ... | ... |\n`; // Indicate truncation } if (totalEntries > maxEntries) { const startIndex = Math.max(maxEntries, totalEntries - maxEntries); for (let i = startIndex; i < totalEntries; i++) { const date = dates[i]; const value = data[date] !== undefined ? data[date] : 'N/A'; text += `| ${date} | ${value} | `; entriesShown++; } } text += `\n*(Showing ${entriesShown} of ${totalEntries} daily values)*\n\n`; } else { text += `- Data: No data available for this period.\n\n`; } } else { text += `- Data: Not available or invalid format.\n\n`; } }); return text; } catch (formatError: any) { console.error('Error formatting POWER data:', formatError); return `Error: Failed to format POWER data. Raw data might be available in resources. Error: ${formatError.message}`; } }