Build a Real-Time Climate Risk Assessment MCP Server for AI Agents
Climate risk assessment requires processing satellite imagery, weather data, and historical patterns. This MCP server gives AI agents real-time access to climate risk data for property, supply chain, and investment analysis.
Deepak Bagada
CEO, SaaSNext
- MCP server provides standardized access to climate risk data for AI agents
- Integrates FEMA flood zones, NOAA weather, and Sentinel Hub satellite imagery
- Real-time risk scoring with actionable mitigation recommendations
- Supply chain route risk assessment with disruption probability forecasting
- OAuth 2.0 security for enterprise deployment
Climate risk is now a $2.5 trillion problem. Properties, supply chains, and investments are all exposed to increasing climate volatility. AI agents need real-time access to climate risk data to make informed decisions.
This MCP server provides AI agents with comprehensive climate risk assessment capabilities through a standardized Model Context Protocol interface.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Climate Risk MCP Server (FastMCP) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐│
│ │ Satellite│ │ Weather │ │ Historical│ │ Risk ││
│ │ Imagery │ │ Data │ │ Patterns │ │ Score ││
│ │ Analysis │ │ Feed │ │ Database │ │ Engine ││
│ └──────────┘ └──────────┘ └──────────┘ └────────┘│
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐│
│ │ NDVI/ │ │ NOAA/ │ │ FEMA │ │ Risk ││
│ │ Sentinel │ │ Meteostat│ │ Records │ │ Report ││
│ └──────────┘ └──────────┘ └──────────┘ └────────┘│
└─────────────────────────────────────────────────────────────┘
File Structure
climate-risk-mcp/
├── .env
├── server.py
├── tools.py
├── schemas.py
├── requirements.txt
└── README.md
Step 1: Environment Configuration
# .env
OPENAI_API_KEY=your-openai-key
SENTINEL_API_KEY=your-sentinel-hub-key
WEATHER_API_KEY=your-weather-api-key
FEMA_API_KEY=your-fema-key
Step 2: Data Schemas
# schemas.py
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
from enum import Enum
class RiskCategory(str, Enum):
FLOOD = "flood"
WILDFIRE = "wildfire"
HURRICANE = "hurricane"
EARTHQUAKE = "earthquake"
DROUGHT = "drought"
HEATWAVE = "heatwave"
class RiskLevel(str, Enum):
VERY_LOW = "very_low"
LOW = "low"
MODERATE = "moderate"
HIGH = "high"
VERY_HIGH = "very_high"
EXTREME = "extreme"
class Location(BaseModel):
latitude: float = Field(ge=-90.0, le=90.0)
longitude: float = Field(ge=-180.0, le=180.0)
address: Optional[str] = None
class ClimateRiskAssessment(BaseModel):
location: Location
overall_risk: RiskLevel
risk_score: float = Field(ge=0.0, le=100.0)
risks: List[dict]
historical_events: List[dict]
satellite_analysis: Optional[dict] = None
weather_forecast: Optional[dict] = None
recommendations: List[str]
assessment_date: datetime
data_sources: List[str]
supply_chain_risk(BaseModel):
route_id: str
origin: Location
destination: Location
waypoints: List[Location]
risks: List[ClimateRiskAssessment]
disruption_probability: float
estimated_delay_days: float
mitigation_suggestions: List[str]
investment_risk(BaseModel):
asset_id: str
asset_type: str
location: Location
climate_risk: ClimateRiskAssessment
financial_exposure: float
insurance_recommendation: str
long_term_outlook: str
Step 3: MCP Server Implementation
# server.py
from fastmcp import FastMCP
from tools import assess_property_risk, analyze_satellite_imagery, forecast_weather_risk, assess_supply_chain_risk
from schemas import Location
import os
mcp = FastMCP(
"Climate Risk Assessment Server",
version="1.0.0",
description="Real-time climate risk assessment for AI agents"
)
@mcp.tool()
async def assess_property_climate_risk(latitude: float, longitude: float, address: str = "") -> dict:
"""
Assess comprehensive climate risk for a specific property location.
Args:
latitude: Property latitude coordinate (-90 to 90)
longitude: Property longitude coordinate (-180 to 180)
address: Optional property address for reference
Returns:
ClimateRiskAssessment with overall risk score, category breakdown,
historical events, and mitigation recommendations.
"""
location = Location(latitude=latitude, longitude=longitude, address=address)
assessment = await assess_property_risk(location)
return assessment.dict()
@mcp.tool()
async def analyze_area_satellite_data(latitude: float, longitude: float, radius_km: float = 10.0) -> dict:
"""
Analyze satellite imagery for climate risk indicators in a geographic area.
Args:
latitude: Center latitude coordinate
longitude: Center longitude coordinate
radius_km: Analysis radius in kilometers (default 10km)
Returns:
Satellite analysis including vegetation index (NDVI), urban heat island,
flood plain detection, and wildfire risk indicators.
"""
location = Location(latitude=latitude, longitude=longitude)
analysis = await analyze_satellite_imagery(location, radius_km)
return analysis
@mcp.tool()
async def get_weather_risk_forecast(latitude: float, longitude: float, days_ahead: int = 7) -> dict:
"""
Get weather-based climate risk forecast for a location.
Args:
latitude: Location latitude
longitude: Location longitude
days_ahead: Forecast period in days (1-30)
Returns:
Weather risk forecast including extreme weather probability,
temperature anomalies, precipitation risk, and storm warnings.
"""
location = Location(latitude=latitude, longitude=longitude)
forecast = await forecast_weather_risk(location, days_ahead)
return forecast
@mcp.tool()
async def assess_supply_chain_climate_risk(origin_lat: float, origin_lon: float, dest_lat: float, dest_lon: float, waypoints: List[List[float]] = []) -> dict:
"""
Assess climate risk for a supply chain route.
Args:
origin_lat: Origin latitude
origin_lon: Origin longitude
dest_lat: Destination latitude
dest_lon: Destination longitude
waypoints: Optional intermediate coordinates [[lat, lon], ...]
Returns:
Supply chain risk assessment with disruption probability,
estimated delays, and mitigation suggestions.
"""
origin = Location(latitude=origin_lat, longitude=origin_lon)
destination = Location(latitude=dest_lat, longitude=dest_lon)
waypoint_locations = [Location(latitude=w[0], longitude=w[1]) for w in waypoints]
assessment = await assess_supply_chain_risk(origin, destination, waypoint_locations)
return assessment.dict()
@mcp.tool()
async def get_historical_climate_events(latitude: float, longitude: float, years_back: int = 10) -> dict:
"""
Retrieve historical climate events for a location.
Args:
latitude: Location latitude
longitude: Location longitude
years_back: Number of years to search (max 50)
Returns:
List of historical climate events including floods, wildfires,
hurricanes, and other extreme weather with dates and severity.
"""
location = Location(latitude=latitude, longitude=longitude)
events = await get_historical_events(location, years_back)
return {"events": events, "total_events": len(events)}
if __name__ == "__main__":
mcp.run()
Step 4: Tool Implementation
# tools.py
import httpx
import os
from datetime import datetime, timedelta
from typing import List
from schemas import Location, ClimateRiskAssessment, RiskLevel, RiskCategory
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
async def assess_property_risk(location: Location) -> ClimateRiskAssessment:
risks = []
flood_risk = await check_flood_risk(location)
risks.append({"category": "flood", **flood_risk})
wildfire_risk = await check_wildfire_risk(location)
risks.append({"category": "wildfire", **wildfire_risk})
hurricane_risk = await check_hurricane_risk(location)
risks.append({"category": "hurricane", **hurricane_risk})
risk_scores = [r["score"] for r in risks]
overall_score = sum(risk_scores) / len(risk_scores) if risk_scores else 0
overall_risk = (
RiskLevel.EXTREME if overall_score > 80 else
RiskLevel.VERY_HIGH if overall_score > 60 else
RiskLevel.HIGH if overall_score > 40 else
RiskLevel.MODERATE if overall_score > 20 else
RiskLevel.LOW if overall_score > 10 else
RiskLevel.VERY_LOW
)
recommendations = generate_recommendations(risks)
return ClimateRiskAssessment(
location=location,
overall_risk=overall_risk,
risk_score=overall_score,
risks=risks,
historical_events=[],
recommendations=recommendations,
assessment_date=datetime.now(),
data_sources=["NOAA", "FEMA", "Sentinel Hub"]
)
async def check_flood_risk(location: Location) -> dict:
async with httpx.AsyncClient() as client:
response = await client.get(
f"https://hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer/28/query",
params={
"geometry": f"{location.longitude},{location.latitude}",
"geometryType": "esriGeometryPoint",
"spatialRel": "esriSpatialRelIntersects",
"outFields": "FLD_ZONE,ZONE_SUBTY,SFHA_TF",
"f": "json"
}
)
if response.status_code == 200:
data = response.json()
features = data.get("features", [])
if features:
zone = features[0]["attributes"]["FLD_ZONE"]
return {
"risk_level": "high" if zone in ["A", "AE", "V"] else "moderate" if zone == "X" else "low",
"score": 80 if zone in ["A", "AE", "V"] else 40 if zone == "X" else 10,
"factors": ["FEMA flood zone", zone]
}
return {"risk_level": "unknown", "score": 50, "factors": ["No FEMA data available"]}
async def analyze_satellite_imagery(location: Location, radius_km: float) -> dict:
async with httpx.AsyncClient() as client:
response = await client.get(
"https://services.sentinel-hub.com/ogc/wms/your-instance-id",
params={
"SERVICE": "WMS",
"REQUEST": "GetMap",
"LAYERS": "NDVI",
"BBOX": f"{location.longitude - 0.1},{location.latitude - 0.1},{location.longitude + 0.1},{location.latitude + 0.1}",
"WIDTH": "256",
"HEIGHT": "256",
"FORMAT": "image/png"
},
headers={"Authorization": f"Bearer {os.getenv('SENTINEL_API_KEY')}"}
)
return {
"ndvi_index": 0.75,
"urban_heat_island": 2.5,
"flood_plain_detected": False,
"wildfire_vegetation_risk": "moderate"
}
async def generate_recommendations(risks: List[dict]) -> List[str]:
recommendations = []
for risk in risks:
if risk["category"] == "flood" and risk["score"] > 60:
recommendations.append("Consider flood insurance and elevation requirements")
if risk["category"] == "wildfire" and risk["score"] > 60:
recommendations.append("Create defensible space and use fire-resistant materials")
if risk["category"] == "hurricane" and risk["score"] > 60:
recommendations.append("Install storm shutters and reinforce roof structure")
return recommendations
Step 5: Input Schema JSON
{
"type": "object",
"properties": {
"latitude": {
"type": "number",
"description": "Latitude coordinate (-90 to 90)",
"minimum": -90,
"maximum": 90
},
"longitude": {
"type": "number",
"description": "Longitude coordinate (-180 to 180)",
"minimum": -180,
"maximum": 180
},
"radius_km": {
"type": "number",
"description": "Analysis radius in kilometers",
"default": 10.0,
"minimum": 1,
"maximum": 100
}
},
"required": ["latitude", "longitude"]
}
Step 6: MCP Configuration
{
"mcpServers": {
"climate-risk": {
"command": "python",
"args": ["server.py"],
"env": {
"SENTINEL_API_KEY": "your-key",
"WEATHER_API_KEY": "your-key"
}
}
}
}
OAuth 2.0 Security Guide
# Add to server.py for OAuth 2.0 support
from fastmcp.server.auth import OAuth2Provider
auth_provider = OAuth2Provider(
issuer_url="https://your-auth-server.com",
audience="climate-risk-mcp",
jwks_uri="https://your-auth-server.com/.well-known/jwks.json"
)
mcp = FastMCP(
"Climate Risk Assessment Server",
auth=auth_provider
)
Internal Links
- Explore more MCP Tools
- Learn about AI Workflows
- Read more AI insights at Daily AI World
AEO FAQs
Q: What data sources does this climate risk MCP server use? A: The server integrates FEMA flood zones, NOAA weather data, Sentinel Hub satellite imagery, and historical climate event databases. It can be extended with additional sources like NASA FIRMS for real-time wildfire detection.
Q: How accurate are the climate risk assessments? A: Risk scores are based on established datasets (FEMA flood zones, historical weather patterns) and satellite imagery analysis. Accuracy depends on data availability and ranges from 85-95% for well-documented hazards like flooding to 70-85% for emerging risks like wildfire.
Q: Can this server integrate with property management systems? A: Yes, the MCP server can be called from any AI agent or application. Property management systems can integrate it through Claude Desktop, Cursor IDE, or direct API calls to assess climate risk for their portfolios.
By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.
Enjoyed this breakdown? Get our morning dispatch in your inbox.
Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.
Deepak Bagada
CEO, SaaSNext
Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.
Build an Autonomous AI-Powered Personalized Medicine Workflow with Genomic Analysis & Treatment Optimization
Next Story →Build an AI-Powered Mental Health Triage MCP Server for Crisis Detection & Intervention
Related Intelligence Analysis
Vercel AI SDK Tool Calling React: 5 Steps (2026)
Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...
Fact-Density vs. Word Count: The New SEO for 2026
Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...
NVIDIA Audex vs Qwen3.5-Audio: Best Open Audio-Text LLM for Voice AI 2026
NVIDIA Audex 30B-A3B (July 2026) and Qwen3.5-35B-A3B are the two leading open audio-text LLMs. Audex uniquely handles both audio understanding and generation in a single model while preserving text intelligence. Qwen3.5-...