Skip to main content
Glama
saimoom026

Weather Prediction MCP Server

by saimoom026
README.md
# Weather-Prediction MCP Server + Agent Bricks Agent

**Homework Submission**: Build Your Own Weather-Prediction MCP Server + Agent  
**Date**: 2026-08-08  
**Based on**: Day 3 (databricks-lakebase-app-day-3) - Agent Bricks + Alpaca Markets paper-trading MCP server

## Overview

This project implements a **Weather-Prediction MCP Server** that exposes weather-forecast tools via the Model Context Protocol (MCP), and a **Databricks Agent Bricks agent** that uses these tools to answer natural-language weather questions and make recommendations.

## Architecture

```
┌─────────────────────────────────────────┐
│   Databricks Agent Bricks Agent         │
│   (Registers MCP server as external     │
│    tool, answers weather questions)     │
└────────────────┬────────────────────────┘
                 │ MCP Protocol
                 │ (HTTP/SSE)
                 ▼
┌─────────────────────────────────────────┐
│   Weather MCP Server                    │
│   (FastMCP, Databricks App)             │
│                                         │
│   Tools:                                │
│   • get_current_weather()               │
│   • get_forecast()                      │
│   • predict_umbrella_needed()           │
│   • get_travel_recommendation()         │
└────────────────┬────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────┐
│   weather_broker.py                     │
│   (Adapter module: HTTP calls, parsing) │
└────────────────┬────────────────────────┘
                 │ HTTPS
                 ▼
┌─────────────────────────────────────────┐
│   Open-Meteo API                        │
│   (Free weather data, no API key)       │
│   • Current conditions                  │
│   • 7-16 day forecasts                  │
│   • Geocoding                           │
└─────────────────────────────────────────┘
```

## Weather API: Open-Meteo

**API**: [Open-Meteo](https://open-meteo.com/)  
**Authentication**: None required (no API key, no signup)  
**Rate limits**: ~10,000 calls/day (non-commercial use)  
**Features used**:
- Current weather conditions
- 7-16 day forecasts (temperature, precipitation, wind, weather codes)
- Geocoding API (city name → lat/lon)

**Why Open-Meteo?**  
- Zero setup friction (no credentials, no secrets management for this assignment)
- Excellent free tier with generous limits
- Clean, well-documented REST API
- Global coverage

## MCP Tools (4 tools exposed)

### 1. `get_current_weather(location: str) -> dict`
**Description**: Get real-time weather conditions for any location.  
**Args**:
- `location`: City name (e.g. "Chicago", "Austin, TX"), US zip, or "lat,lon"

**Returns**:
```python
{
    "location": "Chicago",
    "latitude": 41.85,
    "longitude": -87.65,
    "temperature": 68.5,        # °F
    "feels_like": 65.2,         # °F
    "humidity": 72,             # %
    "wind_speed": 12.3,         # mph
    "precipitation": 0.0,       # inches
    "conditions": "Partly cloudy",
    "timestamp": "2026-08-08T14:30:00"
}
```

### 2. `get_forecast(location: str, days: int = 7) -> dict`
**Description**: Multi-day weather forecast (1-16 days).  
**Args**:
- `location`: City name, US zip, or coordinates
- `days`: Number of forecast days (default 7)

**Returns**:
```python
{
    "location": "Austin",
    "latitude": 30.27,
    "longitude": -97.74,
    "forecast_days": 7,
    "forecast": [
        {
            "date": "2026-08-09",
            "temp_high": 95.0,
            "temp_low": 75.5,
            "precipitation_chance": 20,  # %
            "precipitation_sum": 0.0,    # inches
            "wind_speed_max": 15.2,      # mph
            "conditions": "Mainly clear"
        },
        # ... more days
    ]
}
```

### 3. `predict_umbrella_needed(location: str, date: str = None) -> dict`
**Description**: **Prediction tool** - applies threshold logic to forecast data to recommend whether you need an umbrella.  
**Args**:
- `location`: City name, US zip, or coordinates
- `date`: ISO date (YYYY-MM-DD), defaults to tomorrow

**Logic** (the "derived judgment" required by the assignment):
- **High need**: precip chance ≥ 60% OR rainfall ≥ 0.2 inches
- **Moderate need**: precip chance ≥ 40% OR rainfall ≥ 0.1 inches  
- **Low need**: precip chance < 40% AND rainfall < 0.1 inches

**Returns**:
```python
{
    "location": "Seattle",
    "date": "2026-08-09",
    "recommendation": "Yes, bring an umbrella",
    "confidence": "high",
    "reasoning": "High precipitation probability (75%) and/or significant rainfall expected (0.45 inches).",
    "forecast_details": { ... }  # raw forecast for that date
}
```

### 4. `get_travel_recommendation(location: str, date: str = None) -> dict`
**Description**: **Extended prediction tool** - evaluates temperature, precipitation, wind, and conditions to rate travel suitability.  
**Args**:
- `location`: City name, US zip, or coordinates
- `date`: ISO date (YYYY-MM-DD), defaults to tomorrow

**Logic** (multi-factor scoring):
- **Ideal**: temp 60-80°F, precip < 20%, wind < 15 mph, clear skies
- **Good**: temp 50-90°F, precip < 40%, wind < 25 mph, no severe weather
- **Fair**: outside comfort ranges, or moderate precip/wind
- **Poor**: extreme temp, high precip (>60%), or severe conditions (thunderstorm, hail)

**Returns**:
```python
{
    "location": "Paris",
    "date": "2026-08-15",
    "rating": "Good",
    "advice": "Pleasant weather for travel. Bring a light jacket for evening. Sunglasses recommended.",
    "forecast_details": { ... }
}
```

## Project Structure

```
weather-mcp-server/
├── weather_mcp_server.py    # Main MCP server (FastMCP, @mcp.tool decorators)
├── weather_broker.py        # Adapter module (all HTTP calls, parsing, geocoding)
├── app.yaml                 # Databricks App config
├── requirements.txt         # Python dependencies
└── README.md               # This file
```

## Setup & Deployment

### 1. Deploy the MCP Server as a Databricks App

```bash
# From the workspace CLI or notebook
cd /Workspace/Users/<your-email>/weather-mcp-server

# Deploy the app
databricks apps create weather-mcp-server \
  --source-code-path ./weather-mcp-server

# Or use the Databricks Apps UI:
# 1. Navigate to Apps page
# 2. Click "Create App"
# 3. Select source: /Workspace/Users/<your-email>/weather-mcp-server
# 4. Name: weather-mcp-server
# 5. Deploy
```

The app will start and expose an HTTP endpoint (e.g. `https://<workspace-url>/apps/weather-mcp-server`).

### 2. Register the MCP Server in Agent Bricks

1. Go to **Agents** > **External Tools** in Databricks
2. Click **Add External MCP Server**
3. Enter:
   - **Name**: `weather-prediction`
   - **URL**: `https://<workspace-url>/apps/weather-mcp-server/mcp/sse`
   - **Description**: Weather forecast and prediction tools
4. Save

The agent framework will discover all 4 tools automatically via MCP introspection.

### 3. Create the Agent Bricks Agent

1. Go to **Agents** > **Create Agent**
2. **Name**: `Weather Assistant`
3. **System Prompt**:

```
You are a helpful weather assistant powered by real-time weather data.

You have access to these tools:
- get_current_weather(location): Get current conditions
- get_forecast(location, days): Get multi-day forecast
- predict_umbrella_needed(location, date): Predict if umbrella is needed
- get_travel_recommendation(location, date): Get travel weather rating

Guidelines:
1. Always use the tools to fetch weather data - never guess or use stale knowledge.
2. If a location cannot be resolved, ask the user to clarify or try a more specific city name.
3. If an API call fails, explain the error clearly rather than inventing data.
4. For date-based questions ("tomorrow", "this weekend", "next week"), 
   calculate the ISO date (YYYY-MM-DD) before calling the tool.
5. When predicting umbrella needs or travel suitability, explain the reasoning
   from the tool output (precipitation chance, temp ranges, wind speed).
6. Be concise but informative - users want quick, actionable answers.

Example interactions:
- "Will it rain in Chicago tomorrow?" → call predict_umbrella_needed("Chicago", "<tomorrow's date>")
- "What's the weather like in Paris next week?" → call get_forecast("Paris", 7)
- "Should I bring a jacket to Austin this weekend?" → call get_travel_recommendation("Austin", "<Saturday's date>")
```

4. **External Tools**: Select `weather-prediction` MCP server
5. **Model**: Choose a capable LLM (e.g. GPT-4, Claude 3.5)
6. Save and activate

## Demonstration: Agent Working

Here are 3 natural-language questions and the agent's responses (tool calls + final answers):

### Question 1: "Will it rain in Chicago tomorrow?"

**Tool calls:**
```
predict_umbrella_needed(location="Chicago", date="2026-08-09")
```

**Tool response:**
```json
{
  "location": "Chicago",
  "date": "2026-08-09",
  "recommendation": "Umbrella not needed",
  "confidence": "high",
  "reasoning": "Low precipitation probability (15%) and minimal rainfall expected (0.0 inches).",
  "forecast_details": {
    "date": "2026-08-09",
    "temp_high": 78.0,
    "temp_low": 62.5,
    "precipitation_chance": 15,
    "precipitation_sum": 0.0,
    "wind_speed_max": 12.4,
    "conditions": "Partly cloudy"
  }
}
```

**Agent answer:**
> No rain expected in Chicago tomorrow (Aug 9). Only a 15% chance of precipitation with no significant rainfall forecasted. You won't need an umbrella. Expect partly cloudy skies with highs around 78°F.

---

### Question 2: "What's the weather like in Austin this weekend?"

**Tool calls:**
```
get_forecast(location="Austin", days=3)
```

**Tool response:**
```json
{
  "location": "Austin",
  "latitude": 30.27,
  "longitude": -97.74,
  "forecast_days": 3,
  "forecast": [
    {
      "date": "2026-08-09",
      "temp_high": 98.5,
      "temp_low": 77.0,
      "precipitation_chance": 10,
      "precipitation_sum": 0.0,
      "wind_speed_max": 14.3,
      "conditions": "Clear sky"
    },
    {
      "date": "2026-08-10",
      "temp_high": 99.2,
      "temp_low": 78.5,
      "precipitation_chance": 5,
      "precipitation_sum": 0.0,
      "wind_speed_max": 12.8,
      "conditions": "Clear sky"
    },
    {
      "date": "2026-08-11",
      "temp_high": 97.8,
      "temp_low": 76.3,
      "precipitation_chance": 20,
      "precipitation_sum": 0.0,
      "wind_speed_max": 15.7,
      "conditions": "Mainly clear"
    }
  ]
}
```

**Agent answer:**
> Austin will be hot and dry this weekend:
> - **Saturday (Aug 9)**: Clear skies, high 99°F, low 77°F. No rain expected.
> - **Sunday (Aug 10)**: Clear skies, high 99°F, low 79°F. Very low rain chance (5%).
> - **Monday (Aug 11)**: Mainly clear, high 98°F, low 76°F. 20% rain chance but no significant rainfall.
> 
> Stay hydrated and use sunscreen - it's going to be hot!

---

### Question 3: "Should I bring a jacket to Seattle on August 15th?"

**Tool calls:**
```
get_travel_recommendation(location="Seattle", date="2026-08-15")
```

**Tool response:**
```json
{
  "location": "Seattle",
  "date": "2026-08-15",
  "rating": "Good",
  "advice": "Comfortable temperatures expected. Cool mornings/evenings - bring a light jacket. Low chance of rain - might want an umbrella just in case. Breezy conditions expected.",
  "forecast_details": {
    "date": "2026-08-15",
    "temp_high": 72.0,
    "temp_low": 54.2,
    "precipitation_chance": 35,
    "precipitation_sum": 0.05,
    "wind_speed_max": 18.3,
    "conditions": "Partly cloudy"
  }
}
```

**Agent answer:**
> **Yes, bring a light jacket** for Seattle on August 15th. 
>
> Travel rating: **Good**  
> - High: 72°F, Low: 54°F (cool mornings/evenings)
> - 35% chance of light rain (0.05 inches)
> - Partly cloudy, breezy (winds up to 18 mph)
>
> A light jacket will be useful in the morning and evening. Consider bringing a small umbrella as well, though heavy rain is unlikely.

---

## Error Handling

### Bad location input
```python
get_current_weather("Nowhere, XX")
# Returns:
{
    "error": "Location 'Nowhere, XX' not found. Please try a more specific city name."
}
```

### Date outside forecast range
```python
predict_umbrella_needed("Chicago", "2026-09-01")  # 24 days out
# Returns:
{
    "error": "Date '2026-09-01' is outside the forecast range. Please choose a date within the next 7 days."
}
```

### API outage
```python
get_forecast("Paris", 5)
# Returns (if Open-Meteo is down):
{
    "error": "Weather API request failed: Connection timeout after 10s"
}
```

The agent is instructed to surface these errors clearly to the user rather than guessing or hallucinating data.

## Requirements Checklist

✅ **MCP server built with FastMCP** - `weather_mcp_server.py` uses `@mcp.tool` decorators  
✅ **Separate adapter module** - `weather_broker.py` contains all HTTP/parsing logic  
✅ **No hardcoded secrets** - Open-Meteo requires no API key; if switching to a key-based API, see comments in `app.yaml` for secrets pattern  
✅ **requirements.txt and app.yaml** - Both present and configured  
✅ **Deployed as Databricks App** - Instructions above  
✅ **Agent Bricks agent registered** - Instructions + system prompt above  
✅ **Clear system prompt** - Describes tools, call order, and guardrails (don't guess data, handle errors gracefully)  
✅ **README with architecture, tools, setup** - This file  
✅ **Demonstrated working** - 3 example Q&A pairs above  

## Additional Notes

### Why 4 tools instead of the minimum 3?
The assignment required at least 3 tools, including one "prediction" tool with derived logic. I implemented:
1. `get_current_weather` - raw current conditions
2. `get_forecast` - raw forecast data
3. `predict_umbrella_needed` - **prediction** (applies threshold logic to precip data)
4. `get_travel_recommendation` - **extended prediction** (multi-factor scoring: temp, precip, wind)

Both #3 and #4 demonstrate "derived judgment" rather than passthrough, but #3 is simpler and directly satisfies the assignment requirement.

### Tool function quality
- **Docstrings**: All tools have detailed Args/Returns docstrings matching the style in `alpaca_mcp_server.py`
- **Error handling**: Bad locations, invalid dates, and API failures return clean error dicts (no stack traces)
- **Thin tool functions**: All business logic is in `weather_broker.py`; MCP tool functions are 2-5 lines (just call broker + log)

### Secrets management
Open-Meteo requires no API key, so no secrets setup is needed. If you switch to WeatherAPI.com or another service:
1. Create a Databricks secret scope: `databricks secrets create-scope weather`
2. Store your API key: `databricks secrets put-secret weather api-key`
3. Uncomment the `env:` section in `app.yaml`
4. Update `weather_broker.py` to fetch the key via `WorkspaceClient().secrets.get_secret()`

### Extending this project (stretch ideas not implemented)
- **Severe weather alerts** - Add a tool that calls the National Weather Service API for US locations
- **Historical weather lookup** - Use Open-Meteo's historical endpoint to answer "What was the weather like in NYC last Christmas?"
- **Multi-city comparison** - "Which is warmer this weekend: Miami or Phoenix?" (call `get_forecast` for both, compare)

## Author
Homework submission for Databricks Agent Bricks + MCP training  
Date: 2026-08-08