Skip to main content
Glama
Paszymaja

elicznik-mcp

by Paszymaja
README.md
# elicznik-tauron

Unofficial CLI and MCP server for the **Tauron eLicznik** portal
(https://elicznik.tauron-dystrybucja.pl). Fetch energy consumption, generation
and meter readings from the command line or expose them to AI agents via the
Model Context Protocol.

> Not affiliated with Tauron. Uses the same internal web API the portal uses.

## Features

- **Login** via Keycloak form POST (no browser needed); session cookies cached
  on disk and auto-refreshed.
- **CLI** (`elicznik`) to list meters, fetch energy data and register readings.
- **MCP server** (`elicznik-mcp`, stdio) exposing the same data as tools for
  MCP clients such as OpenCode or Claude.

Available data:

| Data | Resolution |
|------|-----------|
| Consumption / generation / net | hour, day, month, year |
| Tariff zone per hour (`zone`) | hour |
| Cumulative meter register readings | day |

## Requirements

Python 3.10+ and [uv](https://docs.astral.sh/uv/).

## Setup

```bash
uv sync --extra mcp
cp .env.example .env   # then fill in your credentials
```

`.env`:

```
ELICZNIK_USERNAME=your-login-or-email
ELICZNIK_PASSWORD=your-password
# Optional: pick a specific metering point if you have more than one
# ELICZNIK_SITE=123456_123_123
```

Session cookies are cached to `elicznik_session.json` (gitignored) so you only
log in once; the client re-authenticates automatically when the session expires.

## CLI

```bash
# List metering points
uv run elicznik meters

# Hourly consumption for a day (defaults: today, metric=consumption, resolution=hour)
uv run elicznik energy --metric consumption --from 2026-08-24 --to 2026-08-24

# Daily / monthly / yearly totals
uv run elicznik energy --metric consumption --resolution day   --from 2026-08-01 --to 2026-08-26
uv run elicznik energy --metric consumption --resolution month --from 2026-01-01 --to 2026-08-26
uv run elicznik energy --metric generation  --resolution year  --from 2026-01-01 --to 2026-08-26

# Output formats: table (default), csv, json
uv run elicznik energy --metric consumption --resolution day --from 2026-08-01 --to 2026-08-26 --format json

# Cumulative meter register readings (billing readings)
uv run elicznik readings --from 2026-08-01 --to 2026-08-26
uv run elicznik readings --from 2026-08-01 --to 2026-08-26 --generation   # returned energy
```

Metrics: `consumption`, `generation`, `net_consumption`, `net_generation`.

## MCP server

The server exposes four tools:

- `list_meters` — list metering points
- `get_energy(metric, start_date, end_date, resolution)` — one metric, with a
  summed total and per-point values
- `get_readings(start_date, end_date, resolution)` — all four metrics per point
- `get_meter_readings(start_date, end_date, generation)` — cumulative register
  readings

### OpenCode

Add to `~/.config/opencode/opencode.json`:

```json
{
  "mcp": {
    "elicznik": {
      "type": "local",
      "command": ["uv", "run", "--directory", "/home/paszymaja/github_projects/elicznik-tauron", "elicznik-mcp"],
      "enabled": true
    }
  }
}
```

### Claude for Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "elicznik": {
      "command": "uv",
      "args": ["--directory", "/ABSOLUTE/PATH/TO/elicznik-tauron", "run", "elicznik-mcp"]
    }
  }
}
```

The server reads credentials from `.env` in the project directory (or from
`ELICZNIK_USERNAME` / `ELICZNIK_PASSWORD` environment variables).

## Docker

A container image is published to the GitHub Container Registry
(`ghcr.io/paszymaja/elicznik-tauron`). Credentials are read from the
`ELICZNIK_USERNAME` / `ELICZNIK_PASSWORD` environment variables (no `.env`
needed); the session cache is written to `/tmp` (ephemeral).

```bash
# CLI
docker run --rm \
  -e ELICZNIK_USERNAME -e ELICZNIK_PASSWORD \
  ghcr.io/paszymaja/elicznik-tauron:latest meters

docker run --rm \
  -e ELICZNIK_USERNAME -e ELICZNIK_PASSWORD \
  ghcr.io/paszymaja/elicznik-tauron:latest \
  energy --metric consumption --resolution day --from 2026-08-01 --to 2026-08-26

# MCP server over stdio (note the -i flag for stdin)
docker run -i --rm \
  -e ELICZNIK_USERNAME -e ELICZNIK_PASSWORD \
  ghcr.io/paszymaja/elicznik-tauron:latest mcp
```

To build the image locally:

```bash
docker build -t elicznik-tauron .
```

## Contract check

Tauron's API is undocumented and can change without notice. `contract-check`
probes the parts of the API this project depends on and reports, structurally,
whether each still behaves as expected:

```bash
uv run elicznik contract-check
```

It verifies (in order): the Keycloak login flow, the metering-point list, the
hourly CSV export, the chart API, the register-readings API, and the normalized
readings — and exits non-zero if any check fails.

**Privacy:** the output contains only check names and pass/fail flags (plus a
generic structural reason on failure). It never prints metering-point
identifiers, addresses, usernames, or energy values, so it's safe to run in a
public CI pipeline.

### Scheduled CI

The `.github/workflows/contract-check.yml` workflow runs `contract-check` weekly
(Monday 08:00 UTC) and on demand (`workflow_dispatch`), using the
`ELICZNIK_USERNAME` / `ELICZNIK_PASSWORD` repository secrets. On failure it
opens (or comments on) a `contract-check` GitHub issue so a Tauron API change
is surfaced without leaking any data.

## Development

```bash
uv sync --extra mcp
uv run pytest
```

## Notes

- The portal's TLS server negotiates ciphers that Python's default OpenSSL
  policy rejects; the client mounts a `DEFAULT@SECLEVEL=1` adapter as a
  workaround (see `session.py`).
- Hourly CSV timestamps label the *ending* hour; the client normalizes them to
  start-of-hour timestamps matching the chart API convention.
- Timestamps are in local time (Europe/Warsaw), without a timezone offset.

## License

MIT