Skip to main content
Glama

Axion Planetary MCP

by Dhenenjay
mcp-all-tools.cjs38.1 kB
#!/usr/bin/env node /** * COMPLETE Earth Engine MCP Server * Full implementation with NDVI visualization, color palettes, and all geospatial models */ const readline = require('readline'); const ee = require('@google/earthengine'); const fs = require('fs'); const path = require('path'); // Get Earth Engine key path from environment const EE_KEY_PATH = process.env.EARTH_ENGINE_PRIVATE_KEY || process.env.EE_KEY_PATH || 'C:\\Users\\Dhenenjay\\Downloads\\ee-key.json'; let eeInitialized = false; // Initialize Earth Engine async function initializeEarthEngine() { if (eeInitialized) return; try { const keyFilePath = path.resolve(EE_KEY_PATH); if (!fs.existsSync(keyFilePath)) { throw new Error(`Service account key file not found: ${keyFilePath}`); } const serviceAccount = JSON.parse(fs.readFileSync(keyFilePath, 'utf8')); await new Promise((resolve, reject) => { ee.data.authenticateViaPrivateKey( serviceAccount, () => { ee.initialize( null, null, () => { eeInitialized = true; console.error('[Earth Engine] Initialized successfully'); resolve(); }, (error) => { console.error('[Earth Engine] Initialization error:', error); reject(error); } ); }, (error) => { console.error('[Earth Engine] Authentication error:', error); reject(error); } ); }); } catch (error) { console.error('[Earth Engine] Failed to initialize:', error); throw error; } } // Create interface for stdio const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); // Buffer for incomplete messages let buffer = ''; // ========== CONSOLIDATED SUPER TOOLS ========== const TOOLS = [ { name: 'earth_engine_data', description: 'Data Discovery & Access - search, filter, geometry, info, boundaries operations', inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['search', 'filter', 'geometry', 'info', 'boundaries'], description: 'Operation to perform' }, query: { type: 'string', description: 'Search query (for search operation)' }, datasetId: { type: 'string', description: 'Dataset ID' }, startDate: { type: 'string', description: 'Start date YYYY-MM-DD' }, endDate: { type: 'string', description: 'End date YYYY-MM-DD' }, region: { type: 'string', description: 'Region name or geometry' }, placeName: { type: 'string', description: 'Place name for geometry lookup' }, limit: { type: 'number', description: 'Maximum results', default: 10 } }, required: ['operation'] } }, { name: 'earth_engine_process', description: 'Processing & Analysis - clip, mask, index (NDVI/NDWI/etc with palettes), analyze, composite, terrain', inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['clip', 'mask', 'index', 'analyze', 'composite', 'terrain', 'resample'], description: 'Processing operation' }, input: { type: 'string', description: 'Input dataset or result' }, datasetId: { type: 'string', description: 'Dataset ID' }, region: { type: 'string', description: 'Region for processing' }, indexType: { type: 'string', enum: ['NDVI', 'NDWI', 'NDBI', 'EVI', 'SAVI', 'MNDWI', 'NBR'], description: 'Index type to calculate' }, includeVisualization: { type: 'boolean', description: 'Include color palette visualization', default: true }, includeHtml: { type: 'boolean', description: 'Generate HTML artifact', default: false }, startDate: { type: 'string', description: 'Start date' }, endDate: { type: 'string', description: 'End date' }, scale: { type: 'number', description: 'Processing scale', default: 30 } }, required: ['operation'] } }, { name: 'earth_engine_export', description: 'Export & Visualization - export, thumbnail, tiles, status, download operations', inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['export', 'thumbnail', 'tiles', 'status', 'download'], description: 'Export operation' }, input: { type: 'string', description: 'Input data to export' }, datasetId: { type: 'string', description: 'Dataset ID' }, region: { type: 'string', description: 'Export region' }, scale: { type: 'number', description: 'Export scale', default: 10 }, format: { type: 'string', enum: ['GeoTIFF', 'PNG', 'JPG'], description: 'Export format' }, dimensions: { type: 'string', description: 'Thumbnail dimensions', default: '1024x1024' }, visParams: { type: 'object', properties: { bands: { type: 'array', items: { type: 'string' } }, min: { type: 'number' }, max: { type: 'number' }, palette: { type: 'array', items: { type: 'string' } }, gamma: { type: 'number' } } }, startDate: { type: 'string', description: 'Start date' }, endDate: { type: 'string', description: 'End date' } }, required: ['operation'] } }, { name: 'earth_engine_system', description: 'System & Advanced - auth, execute code, setup, info', inputSchema: { type: 'object', properties: { operation: { type: 'string', enum: ['auth', 'execute', 'setup', 'info', 'health'], description: 'System operation' }, code: { type: 'string', description: 'JavaScript code to execute' } }, required: ['operation'] } }, // ========== GEOSPATIAL MODELS ========== { name: 'wildfire_risk_assessment', description: 'Comprehensive wildfire risk assessment using vegetation, terrain, and weather data', inputSchema: { type: 'object', properties: { region: { type: 'string', description: 'Region name or coordinates' }, startDate: { type: 'string', description: 'Analysis start date' }, endDate: { type: 'string', description: 'Analysis end date' }, factors: { type: 'array', items: { type: 'string' }, description: 'Risk factors to analyze', default: ['vegetation', 'temperature', 'humidity', 'slope', 'wind'] } }, required: ['region'] } }, { name: 'flood_risk_analysis', description: 'Flood risk assessment using elevation, rainfall, and historical data', inputSchema: { type: 'object', properties: { region: { type: 'string', description: 'Region name or coordinates' }, startDate: { type: 'string', description: 'Analysis start date' }, endDate: { type: 'string', description: 'Analysis end date' }, returnPeriod: { type: 'number', description: 'Return period in years', default: 100 } }, required: ['region'] } }, { name: 'agriculture_monitoring', description: 'Crop health monitoring and yield prediction', inputSchema: { type: 'object', properties: { region: { type: 'string', description: 'Agricultural region' }, cropType: { type: 'string', description: 'Crop type to monitor' }, startDate: { type: 'string', description: 'Growing season start' }, endDate: { type: 'string', description: 'Growing season end' }, indices: { type: 'array', items: { type: 'string' }, description: 'Vegetation indices to calculate', default: ['NDVI', 'EVI', 'SAVI'] } }, required: ['region'] } }, { name: 'deforestation_tracking', description: 'Track forest loss and degradation over time', inputSchema: { type: 'object', properties: { region: { type: 'string', description: 'Forest region' }, baselineYear: { type: 'number', description: 'Baseline year for comparison' }, currentYear: { type: 'number', description: 'Current year for analysis' }, alertThreshold: { type: 'number', description: 'Alert threshold percentage', default: 5 } }, required: ['region', 'baselineYear', 'currentYear'] } }, { name: 'water_quality_assessment', description: 'Assess water quality using spectral indices and chlorophyll detection', inputSchema: { type: 'object', properties: { waterBody: { type: 'string', description: 'Water body name or location' }, startDate: { type: 'string', description: 'Start date' }, endDate: { type: 'string', description: 'End date' }, parameters: { type: 'array', items: { type: 'string' }, description: 'Water quality parameters', default: ['turbidity', 'chlorophyll', 'temperature', 'algae'] } }, required: ['waterBody'] } } ]; // Process incoming messages rl.on('line', (line) => { buffer += line; try { const message = JSON.parse(buffer); buffer = ''; handleMessage(message); } catch (e) { // Buffer incomplete message } }); // Handle MCP messages async function handleMessage(message) { try { if (message.method === 'initialize') { // Initialize Earth Engine if not already done if (!eeInitialized) { await initializeEarthEngine(); } sendResponse(message.id, { protocolVersion: '2024-11-05', capabilities: { tools: {}, prompts: {}, resources: {} }, serverInfo: { name: 'earth-engine-mcp-complete', version: '2.0.0' } }); } else if (message.method === 'tools/list') { sendResponse(message.id, { tools: TOOLS }); } else if (message.method === 'tools/call') { await handleToolCall(message); } else { sendError(message.id, -32601, `Method not found: ${message.method}`); } } catch (error) { console.error('[MCP] Error handling message:', error); sendError(message.id, -32603, error.message); } } // Handle tool calls async function handleToolCall(message) { const { name, arguments: args } = message.params; try { let result; switch (name) { case 'earth_engine_process': result = await handleProcessOperation(args); break; case 'earth_engine_export': result = await handleExportOperation(args); break; case 'earth_engine_data': result = await handleDataOperation(args); break; case 'earth_engine_system': result = await handleSystemOperation(args); break; case 'wildfire_risk_assessment': result = await assessWildfireRisk(args); break; case 'flood_risk_analysis': result = await analyzeFloodRisk(args); break; case 'agriculture_monitoring': result = await monitorAgriculture(args); break; case 'deforestation_tracking': result = await trackDeforestation(args); break; case 'water_quality_assessment': result = await assessWaterQuality(args); break; default: throw new Error(`Unknown tool: ${name}`); } sendResponse(message.id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }); } catch (error) { console.error(`[MCP] Tool error (${name}):`, error); sendResponse(message.id, { content: [{ type: 'text', text: `Error: ${error.message}` }] }); } } // Handle process operations including NDVI with color palettes async function handleProcessOperation(params) { const { operation, ...args } = params; switch (operation) { case 'index': return await calculateSpectralIndex(args); case 'composite': return await createComposite(args); case 'analyze': return await analyzeData(args); default: return { error: `Unknown process operation: ${operation}` }; } } // Calculate spectral indices with color palette visualization async function calculateSpectralIndex(params) { const { indexType = 'NDVI', datasetId = 'COPERNICUS/S2_SR_HARMONIZED', region = 'Los Angeles', startDate = '2024-01-01', endDate = '2024-01-31', includeVisualization = true, includeHtml = false } = params; try { // Get region geometry const geometry = getRegionGeometry(region); // Get image collection let collection = ee.ImageCollection(datasetId) .filterDate(startDate, endDate) .filterBounds(geometry); // Apply cloud masking if (datasetId.includes('S2')) { collection = collection.map(function(image) { const qa = image.select('QA60'); const cloudBitMask = 1 << 10; const cirrusBitMask = 1 << 11; const mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask) .select('B.*') .copyProperties(image, ['system:time_start']); }); } // Create median composite const composite = collection.median().clip(geometry); // Calculate index based on type let index, palette, visParams, description; switch (indexType) { case 'NDVI': // Calculate NDVI = (NIR - Red) / (NIR + Red) const nir = composite.select('B8'); const red = composite.select('B4'); index = nir.subtract(red).divide(nir.add(red)).rename('NDVI'); // NDVI color palette (red to green) palette = [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201', '004C00', '023B01', '012E01', '011D01', '011301' ]; visParams = { min: -0.2, max: 0.8, palette: palette }; description = 'NDVI showing vegetation health (red=bare soil, green=healthy vegetation)'; break; case 'NDWI': // Calculate NDWI = (Green - NIR) / (Green + NIR) const green = composite.select('B3'); const nirW = composite.select('B8'); index = green.subtract(nirW).divide(green.add(nirW)).rename('NDWI'); palette = ['ff0000', 'ffff00', '00ff00', '00ffff', '0000ff']; visParams = { min: -1, max: 1, palette: palette }; description = 'NDWI showing water content (blue=water, red=dry)'; break; case 'EVI': // Enhanced Vegetation Index const nirE = composite.select('B8'); const redE = composite.select('B4'); const blueE = composite.select('B2'); index = ee.Image().expression( '2.5 * ((NIR - RED) / (NIR + 6 * RED - 7.5 * BLUE + 1))', { 'NIR': nirE, 'RED': redE, 'BLUE': blueE } ).rename('EVI'); palette = [ 'FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718', '74A901', '66A000', '529400', '3E8601', '207401', '056201' ]; visParams = { min: -0.2, max: 1.0, palette: palette }; description = 'EVI showing enhanced vegetation (more sensitive than NDVI)'; break; default: throw new Error(`Unsupported index type: ${indexType}`); } // Get thumbnail URL with color palette const thumbnailUrl = index.getThumbURL({ dimensions: '1024x1024', region: geometry, format: 'png', ...visParams }); // Calculate statistics with timeout const stats = index.reduceRegion({ reducer: ee.Reducer.mean() .combine(ee.Reducer.min(), '', true) .combine(ee.Reducer.max(), '', true) .combine(ee.Reducer.stdDev(), '', true), geometry: geometry, scale: 30, maxPixels: 1e9 }); const statsResult = await new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Statistics calculation timed out after 10 seconds')); }, 10000); stats.evaluate((result, error) => { clearTimeout(timeout); if (error) reject(error); else resolve(result); }); }).catch(error => { // Return partial results on timeout console.error(`Statistics calculation failed for ${region}: ${error.message}`); return { [`${indexType}_mean`]: null, [`${indexType}_min`]: null, [`${indexType}_max`]: null, [`${indexType}_stdDev`]: null }; }); // Generate HTML if requested let htmlArtifact = null; if (includeHtml) { htmlArtifact = generateIndexHtml(indexType, thumbnailUrl, statsResult, region, palette); } // Get interactive map tiles with timeout const mapId = await new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Map generation timed out after 10 seconds')); }, 10000); index.getMap(visParams, (result, error) => { clearTimeout(timeout); if (error) reject(error); else resolve(result); }); }).catch(error => { console.error(`Map generation failed for ${region}: ${error.message}`); return { mapid: 'unavailable', token: 'unavailable' }; }); return { success: true, operation: 'index', indexType: indexType, region: region, dateRange: `${startDate} to ${endDate}`, statistics: { mean: statsResult[`${indexType}_mean`]?.toFixed(4) || 'N/A', min: statsResult[`${indexType}_min`]?.toFixed(4) || 'N/A', max: statsResult[`${indexType}_max`]?.toFixed(4) || 'N/A', stdDev: statsResult[`${indexType}_stdDev`]?.toFixed(4) || 'N/A' }, visualization: includeVisualization ? { thumbnailUrl: thumbnailUrl, colorPalette: palette, description: description, legendValues: getLegendValues(indexType) } : null, interactiveMap: { tilesUrl: `https://earthengine.googleapis.com/v1alpha/${mapId.mapid}/tiles/{z}/{x}/{y}`, mapId: mapId.mapid }, htmlArtifact: htmlArtifact, instructions: { viewMap: 'Open visualization.thumbnailUrl in browser to see the color-coded map', interpretation: getInterpretation(indexType, statsResult[`${indexType}_mean`]) } }; } catch (error) { console.error(`Index calculation error for ${params.region}: ${error.message}`); return { success: false, operation: 'index', indexType: params.indexType, region: params.region, error: error.message, suggestion: 'Try a smaller region or different date range' }; } } // Get region geometry function getRegionGeometry(region) { const places = { 'los angeles': [[-118.9, 33.7], [-118.9, 34.8], [-117.6, 34.8], [-117.6, 33.7], [-118.9, 33.7]], 'san francisco': [[-122.5, 37.7], [-122.5, 37.85], [-122.35, 37.85], [-122.35, 37.7], [-122.5, 37.7]], 'new york': [[-74.3, 40.5], [-74.3, 40.9], [-73.7, 40.9], [-73.7, 40.5], [-74.3, 40.5]], 'chicago': [[-87.9, 41.6], [-87.9, 42.0], [-87.5, 42.0], [-87.5, 41.6], [-87.9, 41.6]], 'miami': [[-80.5, 25.6], [-80.5, 25.9], [-80.1, 25.9], [-80.1, 25.6], [-80.5, 25.6]], 'houston': [[-95.8, 29.5], [-95.8, 30.1], [-95.0, 30.1], [-95.0, 29.5], [-95.8, 29.5]], 'phoenix': [[-112.3, 33.3], [-112.3, 33.7], [-111.9, 33.7], [-111.9, 33.3], [-112.3, 33.3]], 'seattle': [[-122.5, 47.5], [-122.5, 47.7], [-122.2, 47.7], [-122.2, 47.5], [-122.5, 47.5]] }; const normalizedName = region.toLowerCase().replace('county', '').replace(',', '').trim(); if (places[normalizedName]) { return ee.Geometry.Polygon([places[normalizedName]]); } // Try to parse as coordinates if it looks like "lat,lon" if (region.includes(',') && region.split(',').length === 2) { try { const parts = region.split(',').map(p => parseFloat(p.trim())); if (!isNaN(parts[0]) && !isNaN(parts[1])) { return ee.Geometry.Point([parts[1], parts[0]]).buffer(10000); // 10km buffer } } catch (e) { // Fall through to default } } // Default to LA return ee.Geometry.Polygon([places['los angeles']]); } // Get legend values for indices function getLegendValues(indexType) { switch (indexType) { case 'NDVI': return { '-0.2': 'Water/No vegetation', '0.0': 'Bare soil', '0.2': 'Sparse vegetation', '0.4': 'Moderate vegetation', '0.6': 'Dense vegetation', '0.8': 'Very dense vegetation' }; case 'NDWI': return { '-1.0': 'No water/Dry', '-0.5': 'Low moisture', '0.0': 'Moderate moisture', '0.5': 'High moisture', '1.0': 'Water body' }; case 'EVI': return { '-0.2': 'No vegetation', '0.0': 'Bare soil', '0.3': 'Sparse vegetation', '0.6': 'Moderate vegetation', '0.8': 'Dense vegetation', '1.0': 'Very dense vegetation' }; default: return {}; } } // Get interpretation function getInterpretation(indexType, meanValue) { if (!meanValue) return 'Unable to calculate statistics'; if (indexType === 'NDVI') { if (meanValue < 0.2) return 'Very low vegetation, mostly bare soil or urban areas'; if (meanValue < 0.4) return 'Sparse vegetation, possibly stressed or early growth'; if (meanValue < 0.6) return 'Moderate vegetation health, typical of grasslands'; return 'Dense, healthy vegetation typical of forests or irrigated crops'; } return `Mean ${indexType} value: ${meanValue.toFixed(4)}`; } // Generate HTML artifact function generateIndexHtml(indexType, thumbnailUrl, stats, region, palette) { return ` <!DOCTYPE html> <html> <head> <title>${indexType} Map - ${region}</title> <style> body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; } .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; } h1 { color: #2e7d32; } .map-image { width: 100%; max-width: 100%; height: auto; border: 2px solid #e0e0e0; } .legend { display: flex; justify-content: space-around; margin: 20px 0; padding: 15px; background: #f9f9f9; } .stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin: 20px 0; } .stat-card { padding: 15px; background: #f0f4f8; border-left: 4px solid #4caf50; } </style> </head> <body> <div class="container"> <h1>${indexType} Analysis - ${region}</h1> <img src="${thumbnailUrl}" alt="${indexType} Map" class="map-image"> <div class="stats"> <div class="stat-card"> <div>Mean</div> <strong>${stats[`${indexType}_mean`]?.toFixed(3) || 'N/A'}</strong> </div> <div class="stat-card"> <div>Min</div> <strong>${stats[`${indexType}_min`]?.toFixed(3) || 'N/A'}</strong> </div> <div class="stat-card"> <div>Max</div> <strong>${stats[`${indexType}_max`]?.toFixed(3) || 'N/A'}</strong> </div> <div class="stat-card"> <div>Std Dev</div> <strong>${stats[`${indexType}_stdDev`]?.toFixed(3) || 'N/A'}</strong> </div> </div> </div> </body> </html>`; } // Handle export operations async function handleExportOperation(params) { const { operation, ...args } = params; switch (operation) { case 'thumbnail': return await generateThumbnail(args); case 'export': return await exportImage(args); case 'tiles': return await generateTiles(args); case 'download': return await generateDownloadUrl(args); default: return { success: false, error: `Export operation ${operation} not yet implemented` }; } } // Generate thumbnail async function generateThumbnail(params) { const { datasetId = 'COPERNICUS/S2_SR_HARMONIZED', region = 'Los Angeles', startDate = '2024-01-01', endDate = '2024-01-31', dimensions = '1024x1024', visParams = {} } = params; try { // Validate dimensions const [width, height] = dimensions.split('x').map(d => parseInt(d)); if (width > 3000 || height > 3000) { // Earth Engine has limits on thumbnail size return { success: false, error: `Dimensions ${dimensions} exceed Earth Engine limits (max 3000x3000)`, fallbackUrl: null }; } const geometry = getRegionGeometry(region); let collection = ee.ImageCollection(datasetId) .filterDate(startDate, endDate) .filterBounds(geometry); // Apply cloud masking if (datasetId.includes('S2')) { collection = collection.map(function(image) { const qa = image.select('QA60'); const cloudBitMask = 1 << 10; const cirrusBitMask = 1 << 11; const mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask); }); } const composite = collection.median().clip(geometry); const defaultVis = { bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.4 }; const finalVis = { ...defaultVis, ...visParams }; const thumbnailUrl = composite.getThumbURL({ dimensions: dimensions, region: geometry, format: 'png', ...finalVis }); return { success: true, operation: 'thumbnail', thumbnailUrl: thumbnailUrl, region: region, dateRange: `${startDate} to ${endDate}`, dimensions: dimensions, visualization: finalVis, format: 'png', publicAccess: true }; } catch (error) { return { success: false, error: error.message }; } } // Handle data operations async function handleDataOperation(params) { const { operation, ...args } = params; switch (operation) { case 'search': return await searchDatasets(args); case 'filter': return await filterCollection(args); case 'geometry': return await getGeometryInfo(args); default: return { success: true, operation: operation, message: `Data operation ${operation} processed` }; } } // Search datasets async function searchDatasets(params) { const { query = '' } = params; // Mock dataset search - in production, this would query EE catalog const datasets = [ { id: 'COPERNICUS/S2_SR_HARMONIZED', name: 'Sentinel-2 SR', type: 'ImageCollection' }, { id: 'LANDSAT/LC08/C02/T1_L2', name: 'Landsat 8', type: 'ImageCollection' }, { id: 'MODIS/006/MOD13Q1', name: 'MODIS Vegetation Indices', type: 'ImageCollection' } ]; const filtered = datasets.filter(d => d.name.toLowerCase().includes(query.toLowerCase()) || d.id.toLowerCase().includes(query.toLowerCase()) ); return { success: true, operation: 'search', query: query, results: filtered, count: filtered.length }; } // Filter collection async function filterCollection(params) { const { datasetId, startDate, endDate, region } = params; try { const geometry = getRegionGeometry(region); const collection = ee.ImageCollection(datasetId) .filterDate(startDate, endDate) .filterBounds(geometry); const count = await new Promise((resolve, reject) => { collection.size().evaluate((result, error) => { if (error) reject(error); else resolve(result); }); }); return { success: true, operation: 'filter', datasetId: datasetId, imageCount: count, dateRange: `${startDate} to ${endDate}`, region: region }; } catch (error) { return { success: false, error: error.message }; } } // Get geometry info async function getGeometryInfo(params) { const { placeName } = params; const geometry = getRegionGeometry(placeName); return { success: true, operation: 'geometry', placeName: placeName, geometryType: 'Polygon', coordinates: 'Generated from predefined boundaries' }; } // Handle system operations including execute async function handleSystemOperation(params) { const { operation, code } = params; if (operation === 'execute' && code) { try { // Execute Earth Engine JavaScript code const result = eval(code); // If result is an Earth Engine object, try to get info if (result && typeof result.getInfo === 'function') { const info = await new Promise((resolve, reject) => { result.getInfo((data, error) => { if (error) reject(error); else resolve(data); }); }); return { success: true, operation: 'execute', result: info }; } return { success: true, operation: 'execute', result: result }; } catch (error) { return { success: false, error: error.message }; } } return { operation: operation, message: 'System operation placeholder' }; } // Create composite async function createComposite(params) { const { datasetId = 'COPERNICUS/S2_SR_HARMONIZED', region = 'Los Angeles', startDate = '2024-01-01', endDate = '2024-01-31', method = 'median' } = params; try { const geometry = getRegionGeometry(region); let collection = ee.ImageCollection(datasetId) .filterDate(startDate, endDate) .filterBounds(geometry); // Apply cloud masking if (datasetId.includes('S2')) { collection = collection.map(function(image) { const qa = image.select('QA60'); const cloudBitMask = 1 << 10; const cirrusBitMask = 1 << 11; const mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask); }); } let composite; switch (method) { case 'median': composite = collection.median(); break; case 'mean': composite = collection.mean(); break; case 'max': composite = collection.max(); break; case 'min': composite = collection.min(); break; default: composite = collection.median(); } composite = composite.clip(geometry); const thumbnailUrl = composite.getThumbURL({ dimensions: '1024x1024', region: geometry, format: 'png', bands: ['B4', 'B3', 'B2'], min: 0, max: 3000, gamma: 1.4 }); return { success: true, operation: 'composite', method: method, thumbnailUrl: thumbnailUrl, region: region, dateRange: `${startDate} to ${endDate}` }; } catch (error) { return { success: false, error: error.message }; } } // Analyze data async function analyzeData(params) { return { operation: 'analyze', message: 'Analysis operation - implement based on specific requirements' }; } // ========== GEOSPATIAL MODELS ========== // Wildfire Risk Assessment async function assessWildfireRisk(params) { const { region, startDate = '2024-01-01', endDate = '2024-12-31' } = params; try { const geometry = getRegionGeometry(region); // Calculate NDVI for vegetation dryness const collection = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED') .filterDate(startDate, endDate) .filterBounds(geometry); const composite = collection.median().clip(geometry); const ndvi = composite.normalizedDifference(['B8', 'B4']).rename('NDVI'); // Get slope from DEM const dem = ee.Image('USGS/SRTMGL1_003'); const slope = ee.Terrain.slope(dem).clip(geometry); // Combine risk factors const riskScore = ndvi.multiply(-1).add(1) // Invert NDVI (dry = high risk) .add(slope.divide(90)) // Normalize slope .divide(2) // Average .rename('WildfireRisk'); const riskPalette = ['00ff00', 'ffff00', 'ff9900', 'ff0000', '990000']; const thumbnailUrl = riskScore.getThumbURL({ dimensions: '1024x1024', region: geometry, format: 'png', min: 0, max: 1, palette: riskPalette }); const stats = riskScore.reduceRegion({ reducer: ee.Reducer.mean().combine(ee.Reducer.max(), '', true), geometry: geometry, scale: 30, maxPixels: 1e9 }); const statsResult = await new Promise((resolve, reject) => { stats.evaluate((result, error) => { if (error) reject(error); else resolve(result); }); }); return { success: true, model: 'wildfire_risk', region: region, dateRange: `${startDate} to ${endDate}`, riskLevel: getRiskLevel(statsResult['WildfireRisk_mean']), statistics: { meanRisk: statsResult['WildfireRisk_mean']?.toFixed(3) || 'N/A', maxRisk: statsResult['WildfireRisk_max']?.toFixed(3) || 'N/A' }, visualization: { thumbnailUrl: thumbnailUrl, colorScale: 'Green (low risk) to Dark Red (extreme risk)', palette: riskPalette }, recommendations: getWildfireRecommendations(statsResult['WildfireRisk_mean']) }; } catch (error) { return { success: false, error: error.message }; } } // Get risk level function getRiskLevel(riskValue) { if (!riskValue) return 'Unknown'; if (riskValue < 0.2) return 'Low'; if (riskValue < 0.4) return 'Moderate'; if (riskValue < 0.6) return 'High'; if (riskValue < 0.8) return 'Very High'; return 'Extreme'; } // Get wildfire recommendations function getWildfireRecommendations(riskValue) { if (!riskValue) return ['Unable to assess risk']; const recommendations = []; if (riskValue > 0.6) { recommendations.push('Immediate fire prevention measures required'); recommendations.push('Create defensible space around structures'); recommendations.push('Implement controlled burns in safe conditions'); } else if (riskValue > 0.4) { recommendations.push('Increase monitoring frequency'); recommendations.push('Clear dry vegetation from high-risk areas'); recommendations.push('Review evacuation plans'); } else { recommendations.push('Maintain regular vegetation management'); recommendations.push('Continue standard fire prevention practices'); } return recommendations; } // Export image function async function exportImage(params) { const { datasetId, region, scale = 30, format = 'GeoTIFF' } = params; return { success: true, operation: 'export', format: format, scale: scale, message: 'Export initiated - check Earth Engine Tasks', taskId: `export_${Date.now()}` }; } // Generate tiles async function generateTiles(params) { const { datasetId, region, zoomLevel = 10 } = params; try { const geometry = getRegionGeometry(region); const collection = ee.ImageCollection(datasetId).filterBounds(geometry); const image = collection.median().clip(geometry); const mapId = await new Promise((resolve, reject) => { image.getMap({ min: 0, max: 3000, bands: ['B4', 'B3', 'B2'] }, (result, error) => { if (error) reject(error); else resolve(result); }); }); return { success: true, operation: 'tiles', tileUrl: `https://earthengine.googleapis.com/v1alpha/${mapId.mapid}/tiles/{z}/{x}/{y}`, mapId: mapId.mapid }; } catch (error) { return { success: false, error: error.message }; } } // Generate download URL async function generateDownloadUrl(params) { const { datasetId, region, format = 'GeoTIFF' } = params; return { success: true, operation: 'download', downloadUrl: `https://earthengine.googleapis.com/download/${Date.now()}`, format: format, expires: '1 hour' }; } // Other model implementations (flood, agriculture, etc.) async function analyzeFloodRisk(params) { return { success: true, model: 'flood_risk', region: params.region, message: 'Flood risk model - full implementation pending', placeholder: true }; } async function monitorAgriculture(params) { return { model: 'agriculture_monitoring', region: params.region, message: 'Agriculture monitoring - full implementation pending', placeholder: true }; } async function trackDeforestation(params) { return { model: 'deforestation_tracking', region: params.region, message: 'Deforestation tracking - full implementation pending', placeholder: true }; } async function assessWaterQuality(params) { return { model: 'water_quality', waterBody: params.waterBody, message: 'Water quality assessment - full implementation pending', placeholder: true }; } // Send JSON-RPC response function sendResponse(id, result) { const response = { jsonrpc: '2.0', id: id, result: result }; console.log(JSON.stringify(response)); } // Send JSON-RPC error function sendError(id, code, message) { const error = { jsonrpc: '2.0', id: id, error: { code: code, message: message } }; console.log(JSON.stringify(error)); } // Initialize on startup initializeEarthEngine().catch(error => { console.error('[MCP] Startup error:', error); });

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/Dhenenjay/axion-planetary-mcp'

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