Skip to main content
Glama
README.md
# Open-Meteo Weather MCP Server

A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides weather data using the free [Open-Meteo API](https://open-meteo.com/). Built with [FastMCP](https://github.com/jlowin/fastmcp).

**No API key required** β€” Open-Meteo is free for non-commercial use.

## Features

- 🌍 **Geocoding** β€” Search for any city or location worldwide
- 🌑️ **Current Weather** β€” Temperature, humidity, wind, precipitation, pressure
- πŸ“… **Daily Forecast** β€” Up to 16 days with high/low temps, UV index, sunrise/sunset
- ⏰ **Hourly Forecast** β€” Detailed hour-by-hour predictions
- πŸ™οΈ **City Lookup** β€” Convenience tool combining search + weather in one call
- 🌐 **Unit Options** β€” Celsius/Fahrenheit, km/h/mph/knots, mm/inch

## Installation

### Prerequisites

- Python 3.10+

### Install from Source

```bash
# Clone the repository
git clone <repository-url>
cd weather-mcp

# Create virtual environment
python -m venv .venv
source .venv/bin/activate  # Linux/macOS
# or: .venv\Scripts\activate  # Windows

# Install in development mode
pip install -e .

# Or install with dev dependencies
pip install -e ".[dev]"
```

### Install Dependencies Only

```bash
pip install fastmcp httpx
```

## Quick Start

### Run with CLI Command

```bash
weather-mcp
```

### Run as Module

```bash
python -m weather_mcp
```

### Run with Options

```bash
weather-mcp --host 0.0.0.0 --port 8080
python -m weather_mcp --host 0.0.0.0 --port 8080
```

### Run Programmatically

```python
from weather_mcp import WeatherMCPServer

server = WeatherMCPServer()
server.run()
```

### CLI Options

| Option | Default | Description |
|--------|---------|-------------|
| `--host` | `127.0.0.1` | Host to bind to |
| `--port` | `8001` | Port to listen on |
| `--transport` | `streamable-http` | Transport type (`streamable-http`, `http`, `stdio`) |
| `--timeout` | `30.0` | API request timeout in seconds |

## MCP Tools

### search_location

Find coordinates for a city or place name.

**Parameters:**
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `name` | string | required | City name, postal code, or place name |
| `count` | int | 5 | Number of results (1-100) |
| `language` | string | "en" | Language for results |

**Example Response:**
```json
{
  "results": [
    {
      "name": "Berlin",
      "latitude": 52.52437,
      "longitude": 13.41053,
      "country": "Germany",
      "country_code": "DE",
      "admin1": "Berlin",
      "timezone": "Europe/Berlin",
      "population": 3426354,
      "elevation": 74.0
    }
  ]
}
```

### get_current_weather

Get current weather conditions for a location.

**Parameters:**
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `latitude` | float | required | Latitude coordinate |
| `longitude` | float | required | Longitude coordinate |
| `temperature_unit` | string | "celsius" | `celsius` or `fahrenheit` |
| `wind_speed_unit` | string | "kmh" | `kmh`, `ms`, `mph`, or `kn` |
| `timezone` | string | "auto" | Timezone (e.g., `Europe/Berlin`, `auto`) |

**Example Response:**
```json
{
  "location": {
    "latitude": 52.52,
    "longitude": 13.41,
    "elevation": 38.0,
    "timezone": "Europe/Berlin"
  },
  "time": "2024-01-15T14:00",
  "temperature": {
    "value": 5.2,
    "feels_like": 2.1,
    "unit": "Β°C"
  },
  "humidity": {"value": 75, "unit": "%"},
  "conditions": {
    "code": 3,
    "description": "Overcast",
    "is_day": true
  },
  "precipitation": {
    "total": 0.0,
    "rain": 0.0,
    "snowfall": 0.0,
    "unit": "mm"
  },
  "wind": {
    "speed": 15.5,
    "direction": 270,
    "gusts": 25.0,
    "unit": "km/h"
  },
  "pressure": {
    "sea_level": 1013.25,
    "surface": 1010.0,
    "unit": "hPa"
  },
  "cloud_cover": {"value": 100, "unit": "%"}
}
```

### get_weather_forecast

Get daily weather forecast for a location.

**Parameters:**
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `latitude` | float | required | Latitude coordinate |
| `longitude` | float | required | Longitude coordinate |
| `forecast_days` | int | 7 | Number of days (1-16) |
| `temperature_unit` | string | "celsius" | `celsius` or `fahrenheit` |
| `wind_speed_unit` | string | "kmh" | `kmh`, `ms`, `mph`, or `kn` |
| `precipitation_unit` | string | "mm" | `mm` or `inch` |
| `timezone` | string | "auto" | Timezone |

**Example Response:**
```json
{
  "location": {...},
  "forecast_days": 7,
  "daily": [
    {
      "date": "2024-01-15",
      "conditions": {
        "code": 3,
        "description": "Overcast"
      },
      "temperature": {
        "max": 8.5,
        "min": 2.1,
        "unit": "Β°C"
      },
      "sun": {
        "sunrise": "2024-01-15T07:45",
        "sunset": "2024-01-15T16:30",
        "daylight_seconds": 31500,
        "sunshine_seconds": 12000
      },
      "uv_index": 1.5,
      "precipitation": {
        "total": 2.5,
        "probability": 60,
        "unit": "mm"
      },
      "wind": {
        "speed": 20.0,
        "direction": 225,
        "gusts": 35.0,
        "unit": "km/h"
      }
    }
  ]
}
```

### get_hourly_forecast

Get detailed hourly weather forecast.

**Parameters:**
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `latitude` | float | required | Latitude coordinate |
| `longitude` | float | required | Longitude coordinate |
| `forecast_days` | int | 2 | Number of days (1-16) |
| `temperature_unit` | string | "celsius" | `celsius` or `fahrenheit` |
| `wind_speed_unit` | string | "kmh" | `kmh`, `ms`, `mph`, or `kn` |
| `precipitation_unit` | string | "mm" | `mm` or `inch` |
| `timezone` | string | "auto" | Timezone |

**Example Response:**
```json
{
  "location": {...},
  "total_hours": 48,
  "hourly": [
    {
      "time": "2024-01-15T00:00",
      "conditions": {
        "code": 0,
        "description": "Clear sky",
        "is_day": false
      },
      "temperature": {
        "value": 3.5,
        "feels_like": 1.2,
        "unit": "Β°C"
      },
      "humidity": 85,
      "precipitation": {
        "total": 0.0,
        "probability": 10
      },
      "cloud_cover": 0,
      "visibility": 24000,
      "wind": {
        "speed": 8.5,
        "direction": 180,
        "gusts": 15.0
      }
    }
  ]
}
```

### get_weather_by_city

Convenience tool that combines location search + current weather + forecast in one call.

**Parameters:**
| Name | Type | Default | Description |
|------|------|---------|-------------|
| `city` | string | required | City name (e.g., "Paris", "New York, NY") |
| `forecast_days` | int | 7 | Number of days (1-16) |
| `temperature_unit` | string | "celsius" | `celsius` or `fahrenheit` |
| `wind_speed_unit` | string | "kmh" | `kmh`, `ms`, `mph`, or `kn` |

**Example Response:**
```json
{
  "city": {
    "name": "Paris",
    "latitude": 48.8566,
    "longitude": 2.3522,
    "country": "France",
    "admin1": "Île-de-France",
    "timezone": "Europe/Paris"
  },
  "current": {...},
  "forecast": {...}
}
```

## MCP Host Configuration

To use this server with an MCP-compatible host, add it to your MCP configuration:

### HTTP Transport (default)

```json
{
  "mcpServers": {
    "weather": {
      "url": "http://127.0.0.1:8001/mcp"
    }
  }
}
```

### stdio Transport

Using the CLI command (after `pip install -e .`):

```json
{
  "mcpServers": {
    "weather": {
      "command": "weather-mcp",
      "args": ["--transport", "stdio"]
    }
  }
}
```

Or using the module directly:

```json
{
  "mcpServers": {
    "weather": {
      "command": "python",
      "args": ["-m", "weather_mcp", "--transport", "stdio"]
    }
  }
}
```

## Project Structure

```
weather-mcp/
β”œβ”€β”€ pyproject.toml       # Project configuration and dependencies
β”œβ”€β”€ README.md
└── src/
    └── weather_mcp/
        β”œβ”€β”€ __init__.py      # Package exports
        β”œβ”€β”€ __main__.py      # CLI entry point
        β”œβ”€β”€ constants.py     # API endpoints, enums, weather codes
        β”œβ”€β”€ models.py        # Data classes for weather data
        β”œβ”€β”€ clients.py       # HTTP clients for Open-Meteo APIs
        β”œβ”€β”€ tools.py         # MCP tool definitions
        └── server.py        # Main server class
```

## Using Components Directly

You can use the API clients independently of the MCP server:

```python
import asyncio
from weather_mcp import GeocodingClient, WeatherClient

async def main():
    # Search for a city
    geocoding = GeocodingClient()
    locations = await geocoding.search("Tokyo")
    print(f"Found: {locations[0].name}, {locations[0].country}")
    
    # Get weather
    weather = WeatherClient()
    current = await weather.get_current(
        locations[0].latitude,
        locations[0].longitude
    )
    print(f"Temperature: {current['temperature']['value']}Β°C")

asyncio.run(main())
```

## Data Source

All weather data is provided by [Open-Meteo](https://open-meteo.com/).

- Free for non-commercial use
- No API key required
- Global coverage
- Updates every 15 minutes

## License

MIT