Skip to main content
Glama
dolgova

MCP Weather Server

by dolgova
README.md
# MCP Weather Server

Minimal MCP server that exposes weather data via tools using the [Open-Meteo](https://open-meteo.com/) API (no API key required).

---

## Architecture

The project has three parts: a **client** (Cursor or the Python test client), the **MCP server** (this repo), and the **Open-Meteo API**. The client and server talk over **stdio** (stdin/stdout); the server talks to the API over **HTTPS**.

```mermaid
flowchart LR
  subgraph local [Your machine]
    Client[MCP Client]
    Server[MCP Server]
  end
  API[Open-Meteo API]
  Client <-->|"stdio (JSON-RPC)"| Server
  Server -->|"HTTPS GET"| API
```

**How client and server communicate:**

1. The client starts the server as a **subprocess** and connects to it via **stdio** (standard input/output).
2. Messages are **JSON-RPC** over stdio: the client sends requests (e.g. "list tools", "call tool X with args Y"); the server responds with results.
3. When a tool is called, the server runs the tool logic (e.g. `get_current_weather`), which may call the Open-Meteo API; the server then sends the tool result back to the client over stdio.

```mermaid
sequenceDiagram
  participant Client as MCP Client
  participant Server as MCP Server
  participant API as Open-Meteo API

  Client->>Server: Initialize (stdio)
  Server-->>Client: Ready

  Client->>Server: ListTools
  Server-->>Client: get_current_weather, get_forecast

  Client->>Server: CallTool get_current_weather(5.98, 80.43)
  Server->>API: GET forecast?latitude=5.98&longitude=80.43
  API-->>Server: JSON weather data
  Server-->>Client: "Temperature: ...°C, Humidity: ...%..."
```

**Summary:**

| Component | Role |
|-----------|------|
| **MCP Client** | Starts the server process, sends JSON-RPC over stdin, reads responses from stdout. Can be Cursor, the Python `client.py`, or MCP Inspector. |
| **MCP Server** | Runs as a subprocess. Listens on stdin for requests, executes tools (calling `weather.get_weather`), returns results on stdout. |
| **Open-Meteo API** | External HTTP API. The server calls it when a weather tool is invoked; the client never talks to it directly. |

---

## Setup

**Windows (PowerShell):**

```bash
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
```

**Linux / WSL:**

```bash
# If venv fails, install first: sudo apt install python3.10-venv
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

If you cannot create a venv (e.g. WSL without `python3-venv`), install into your user site-packages and use `python3`:

```bash
pip install --user -r requirements.txt
```

---

## Run the server (for Cursor / other MCP hosts)

```bash
python server.py
# or on Linux/WSL: python3 server.py
```

The server uses **stdio** transport: it reads from stdin and writes to stdout. Cursor (or another MCP host) starts this process and talks to it over those streams.

---

## How to use the Python client

The **client** (`client.py`) is a small script that connects to the MCP server via stdio and calls the weather tools. Use it to verify that the server works without Cursor.

**Steps:**

1. **From the project directory**, with dependencies installed (see Setup):

   **Windows:**
   ```bash
   python client.py
   ```

   **Linux / WSL:**
   ```bash
   python3 client.py
   ```

2. **What the client does:**
   - Starts `server.py` as a subprocess.
   - Connects to it over stdio (stdin/stdout).
   - Sends **ListTools** and prints the tool names.
   - Calls **get_current_weather(5.98, 80.43)** (Weligama, Sri Lanka) and prints the result.
   - Calls **get_forecast(5.98, 80.43, days=3)** (Weligama, 3 days) and prints the result.

3. **Example output (Weligama, Sri Lanka):**

   ```
   Tools: ['get_current_weather', 'get_forecast']

   --- Weligama, Sri Lanka — current weather ---
   Temperature: 28.5°C, Humidity: 75%, Wind: 5.2 km/h, Weather code: 1

   --- Weligama, Sri Lanka — 3-day forecast ---
   Temperature: 28.5°C, Humidity: 75%, Wind: 5.2 km/h, Weather code: 1
   2026-02-08: max 29.1°C, min 25.2°C
   2026-02-09: max 29.5°C, min 25.8°C
   2026-02-10: max 29.2°C, min 25.5°C
   ```

You do **not** need to run `server.py` in another terminal; the client starts it automatically.

---

## Cursor MCP config

Add the server to Cursor so the editor can call the weather tools (e.g. from chat).

**Settings → MCP** (or edit `~/.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "weather": {
      "command": "python",
      "args": ["C:\\Users\\dolgo\\Desktop\\ai_projects\\mcp_server\\server.py"]
    }
  }
}
```

**WSL:** use `python3` and the Linux path to `server.py`:

```json
"command": "python3",
"args": ["/mnt/c/Users/dolgo/Desktop/ai_projects/mcp_server/server.py"]
```

Optional: use the venv Python so Cursor uses the same environment:

```json
"command": "C:\\Users\\dolgo\\Desktop\\ai_projects\\mcp_server\\.venv\\Scripts\\python.exe",
"args": ["C:\\Users\\dolgo\\Desktop\\ai_projects\\mcp_server\\server.py"]
```

---

## Tools

| Tool | Arguments | Description |
|------|-----------|-------------|
| **get_current_weather** | `latitude`, `longitude` | Current temperature, humidity, wind speed, weather code. |
| **get_forecast** | `latitude`, `longitude`, `days` (1–7) | Current conditions plus daily min/max for the next `days` days. |
| **get_model_forecast** | `latitude`, `longitude` | Next-day max temperature from the trained ML model (requires training first). |

Example: “What’s the weather in Weligama?” → use latitude **5.98**, longitude **80.43** (Weligama, Sri Lanka).

---

## ML predictive model (next-day max temperature)

A small **Random Forest** model predicts **tomorrow's max temperature** from today's daily weather (max/min temp, humidity, wind, day of year). It is trained on historical data from Open-Meteo and exposed as the **get_model_forecast** MCP tool.

### One-time setup: fetch data and train

1. **Fetch historical daily weather** (e.g. Weligama, 2022–today):

   ```bash
   python scripts/fetch_history.py
   # optional: --lat 5.98 --lon 80.43 --start 2022-01-01 --end 2025-02-06
   ```

   Output: `data/weligama_history.csv`.

2. **Train the model:**

   ```bash
   python scripts/train.py
   # optional: --data data/weligama_history.csv --out model/model.joblib
   ```

   Output: `model/model.joblib` (and MAE in °C on a held-out set).

3. **Use the tool:** After training, **get_model_forecast(latitude, longitude)** uses today's conditions (from the forecast API) and the trained model to return a predicted tomorrow max temperature.

### Flow

- **Training:** `scripts/fetch_history.py` → historical daily data → `scripts/train.py` → `model/model.joblib`.
- **Inference:** MCP tool **get_model_forecast** calls the forecast API for today's daily values, builds the feature vector, runs the model, returns e.g. `"Model predicts tomorrow's max temperature: 29.2°C"`.

Maintenance

ActivityInactive
ResponsivenessNo issues