aakashdg's picture
feat (GEE soil MCP server implementation)
ca9ccdd verified
"""
Soil Properties Server using Google Earth Engine
"""
import ee
import os
import json
from typing import Dict, Any
class SoilPropertiesServer:
"""Google Earth Engine Soil Server"""
def __init__(self):
self._initialize_gee()
self.layers = {
"clay": "OpenLandMap/SOL/SOL_CLAY-WFRACTION_USDA-3A1A1A_M/v02",
"sand": "OpenLandMap/SOL/SOL_SAND-WFRACTION_USDA-3A1A1A_M/v02",
"phh2o": "OpenLandMap/SOL/SOL_PH-H2O_USDA-4C1A2A_M/v02",
"soc": "OpenLandMap/SOL/SOL_ORGANIC-CARBON_USDA-6A1C_M/v02"
}
self.depth_band = "b0"
def _initialize_gee(self):
"""Initialize GEE with service account"""
try:
# Check if service account key is provided
service_account_key = os.environ.get('GEE_SERVICE_ACCOUNT_KEY')
if service_account_key:
# Parse JSON key
credentials_dict = json.loads(service_account_key)
credentials = ee.ServiceAccountCredentials(
credentials_dict['client_email'],
key_data=service_account_key
)
ee.Initialize(credentials)
print("βœ… GEE initialized with service account")
else:
# Fallback to default credentials (for local development)
ee.Initialize(project='MCPprototypeGEE')
print("βœ… GEE initialized with default credentials")
except Exception as e:
print(f"⚠️ GEE initialization failed: {str(e)}")
raise
async def get_data(self, lat: float, lon: float) -> Dict[str, Any]:
"""Get soil properties at coordinate"""
try:
point = ee.Geometry.Point([lon, lat])
results = {}
for prop_name, image_id in self.layers.items():
try:
image = ee.Image(image_id).select(self.depth_band)
value = image.sample(point, 250).first().get(self.depth_band).getInfo()
if value is not None:
if prop_name in ['clay', 'sand']:
results[prop_name] = round(value / 10, 1)
elif prop_name == 'phh2o':
results[prop_name] = round(value / 10, 1)
elif prop_name == 'soc':
results[prop_name] = round(value / 10, 1)
else:
results[prop_name] = None
except:
results[prop_name] = None
if not any(v is not None for v in results.values()):
return {
"status": "error",
"error": "No soil data available"
}
silt = None
if results.get("clay") and results.get("sand"):
silt = round(100 - results["clay"] - results["sand"], 1)
return {
"status": "success",
"data": {
"clay_percent": results.get("clay"),
"sand_percent": results.get("sand"),
"silt_percent": silt,
"pH": results.get("phh2o"),
"organic_carbon_g_kg": results.get("soc"),
"data_source": "Google Earth Engine (OpenLandMap)",
"location": {"latitude": lat, "longitude": lon},
"depth": "0-5cm"
}
}
except Exception as e:
return {
"status": "error",
"error": str(e)
}