Skip to main content
Glama
cmer81

infoclimat-mcp

by cmer81
README.md
# infoclimat-mcp

A [FastMCP](https://github.com/jlowin/fastmcp) server that exposes [Infoclimat](https://www.infoclimat.fr/) weather data via the Model Context Protocol (MCP). The server proxies requests to the Infoclimat API, injecting your API token server-side so clients never see it.

## Tools

| Tool | Description |
|------|-------------|
| `list_stations` | List stations with optional filters (département, pays, genre, active_only) |
| `search_stations` | Search stations by name or département — use this to resolve a place name to station IDs |
| `find_nearest_stations` | Find stations within a radius of a lat/lon point |
| `get_observations` | Observations for one or more stations over a date range — raw (~10 min resolution) or aggregated daily (`aggregate="daily"`) |
| `get_latest` | Latest observation for each requested station |
| `get_precipitation_summary` | Precipitation totals over a period, with lat/lon for mapping |

## Installation

### With uv (recommended)

```bash
git clone <repo>
cd infoclimat-mcp
uv sync
```

### With pip

```bash
pip install fastmcp httpx cachetools python-dotenv
```

## Configuration

Copy `.env.example` to `.env` and fill in your token:

```bash
cp .env.example .env
```

```env
INFOCLIMAT_TOKEN=your_token_here
MCP_HOST=0.0.0.0   # optional, default 0.0.0.0
MCP_PORT=8000      # optional, default 8000
```

Get a token at [infoclimat.fr](https://www.infoclimat.fr/).

## Running

```bash
uv run python main.py
```

The server starts an SSE endpoint at `http://0.0.0.0:8000/sse`.

## Docker

The image is published automatically to GitHub Container Registry on every push to `master` and on version tags.

```bash
docker pull ghcr.io/cmer81/infoclimat-mcp:latest
```

Run the server:

```bash
docker run -d \
  -e INFOCLIMAT_TOKEN=your_token_here \
  -p 8000:8000 \
  ghcr.io/cmer81/infoclimat-mcp:latest
```

Optional environment variables:

| Variable | Default | Description |
|----------|---------|-------------|
| `INFOCLIMAT_TOKEN` | *(required)* | Your Infoclimat API token |
| `MCP_HOST` | `0.0.0.0` | Host to bind |
| `MCP_PORT` | `8000` | Port to listen on |

The SSE endpoint is available at `http://localhost:8000/sse`.

> **Note:** Never pass `INFOCLIMAT_TOKEN` as a build argument — always supply it at runtime via `-e`.

## MCP Client Configuration

> The Docker image exposes the same SSE endpoint (`/sse`) on port 8000. The configuration below applies whether you're running the server directly or via Docker.

### Claude Desktop (remote server via SSE)

> **Note:** Claude Desktop natively uses stdio for *local* MCP servers. The config below assumes the server is deployed remotely (e.g., behind a reverse proxy with TLS).

```json
{
  "mcpServers": {
    "infoclimat": {
      "transport": "sse",
      "url": "https://your-server.example.com/sse"
    }
  }
}
```

### Generic HTTP/SSE MCP client

```
SSE endpoint: https://your-server.example.com/sse
```

## Reverse proxy (TLS)

Example Caddyfile for TLS termination:

```
your-server.example.com {
    reverse_proxy localhost:8000
}
```

## Daily Aggregation

`get_observations` accepts an optional `aggregate` parameter:

| Value | Behaviour |
|-------|-----------|
| `"raw"` (default) | Returns all raw ~10-minute observations |
| `"daily"` | Returns compact per-day statistics — suitable for injecting into LLM context |

Example daily response per station:

```json
{
  "STATIC0183": {
    "station_name": "Sainte-Radegonde",
    "period": { "start": "2026-03-01", "end": "2026-03-21" },
    "daily": [
      {
        "date": "2026-03-01",
        "temp_min": 2.2,
        "temp_mean": 6.9,
        "temp_max": 13.8,
        "humidity_mean": 79.0,
        "wind_mean_kmh": 7.2,
        "wind_gust_max_kmh": 63.7,
        "pressure_mean": 1023.8,
        "precip_mm": 0.0
      }
    ],
    "summary": {
      "temp_min_abs": -4.1,
      "temp_max_abs": 21.4,
      "temp_mean": 8.2,
      "precip_total_mm": 29.8,
      "days_count": 21
    }
  }
}
```

Fields with all-null source values are omitted. `precip_mm` is the last `pluie_cumul_0h` value of the day (cumul since midnight).

## Caching

- Station list: cached 1 hour in memory
- Observations: cached 10 minutes per (stations, start, end) key
- Cache is lost on server restart