pylanis
Zugriff auf das Schulportal Hessen (Lanis) aus Python, aus dem Terminal und aus KI-Assistenten: Vertretungsplan, Stundenplan, Kalender, Hausaufgaben, Nachrichten, Dateien und mehr.
pylanis ist ein Paket mit drei gleichwertigen Zugängen zu denselben Daten:
| Zugang | Für | Start |
|---|---|---|
| Python-SDK | eigene Programme und Automatisierungen | from pylanis import Lanis |
| Kommandozeile | das Terminal und Shell-Skripte (JSON-Ausgabe) | lanis <befehl> |
| MCP-Server | KI-Assistenten wie Claude | lanis mcp |
pylanis liest nur. Es verändert keine Daten im Schulportal.
Installation
pylanis braucht Python 3.11 oder neuer und wird auf PyPI veröffentlicht.
# Als Bibliothek in einem Projekt
pip install pylanis # oder: uv add pylanis
# Den Befehl lanis global installieren
uv tool install pylanis # oder: pipx install pylanis
# Ohne Installation ausprobieren
uvx --from pylanis lanis schools
Kommandozeile und MCP-Server gibt es auch als Docker-Image udondan/lanis (amd64 und arm64), ganz ohne Python:
docker run --rm udondan/lanis schools
Das Image führt den Befehl lanis aus. Ohne Argument startet es den MCP-Server.
Die Images sind mit cosign signiert. So prüfst du, dass ein Image vom Release-Workflow dieses Repositorys stammt:
cosign verify udondan/lanis:latest \
--certificate-identity-regexp '^https://github\.com/udondan/pylanis/\.github/workflows/publish\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Anmeldung
Du brauchst einen Lanis-Account und die Schul-ID deiner Schule. Die Schul-ID findest du ohne Anmeldung:
uvx --from pylanis lanis --format markdown schools | grep -i "musterstadt"
Es gibt drei Arten, sich anzumelden. Das SDK nimmt die Zugangsdaten als Parameter, Kommandozeile und MCP-Server lesen sie aus Umgebungsvariablen (Lanis.from_env() im SDK ebenso).
| Art | Umgebungsvariablen | SDK-Parameter |
|---|---|---|
| Benutzername & Passwort (empfohlen) | LANIS_SCHOOL_ID, LANIS_USERNAME, LANIS_PASSWORD |
school_id, username, password |
| Schule nach Name & Stadt | LANIS_SCHOOL_NAME, LANIS_SCHOOL_CITY, LANIS_USERNAME, LANIS_PASSWORD |
school_name, school_city, username, password |
| Session-Cookie (kein Passwort) | LANIS_SCHOOL_ID, LANIS_SESSION_ID |
school_id, session_id |
Mit Benutzername und Passwort meldet sich pylanis automatisch neu an, wenn die Session abläuft. Ein Session-Cookie läuft irgendwann ab und muss dann ersetzt werden.
Session speichern (optional): Mit LANIS_DATA_DIR (SDK: data_dir) wird die Session in session.json in diesem Verzeichnis gespeichert, sodass nach einem Neustart keine neue Anmeldung nötig ist. Die Datei ist nur für dich lesbar. Ohne diese Einstellung bleibt die Session nur im Speicher.
Verfügbare Daten
Alle drei Zugänge bieten dieselben Daten:
| Daten | SDK (Lanis) |
Kommandozeile (lanis) |
MCP-Tool |
|---|---|---|---|
| Schulen mit ID (ohne Anmeldung) | get_schools() |
schools |
get_schools |
| Vertretungsplan | get_substitution_plan() |
substitutions |
get_substitution_plan |
| Stundenplan | get_timetable() |
timetable |
get_timetable |
| Lerngruppen/Kurse | get_learning_groups() |
learning-groups |
get_learning_groups |
| Kalender für einen Zeitraum | get_calendar(start, end) |
calendar --start … --end … |
get_calendar |
| Kalender des aktuellen Monats | get_calendar_of_month() |
calendar |
get_calendar_of_month |
| Aufgaben aus „Mein Unterricht" | get_tasks() |
tasks |
get_tasks |
| Nachrichten | get_conversations(number=10) |
conversations [--number N] |
get_conversations |
| Dateispeicher | get_file_storage(folder_id=None) |
files [--folder ID] |
get_file_storage |
| Dateiverteilung | get_file_distribution() |
file-distribution |
get_file_distribution |
| Aktive Wahlen | get_votes() |
votes |
get_votes |
| App-Kacheln und Ordner im Dashboard | get_apps(), get_folders() |
apps, folders |
get_apps, get_folders |
| Unterstützte Apps der Schule | get_available_apps(), is_app_available() |
available-apps, check-app NAME |
get_available_apps, check_app_availability |
Hinweise:
- Mit
include_responsible=True(SDK),--responsible(Kommandozeile) bzw.include_responsible(MCP) enthalten Kalendertermine die verantwortliche Person. Dafür ist pro Termin eine zusätzliche Anfrage nötig, das kann bei vielen Terminen dauern. number=-1lädt alle Nachrichten und belastet den Lanis-Server stark. Bitte sparsam verwenden.
Python-SDK
from datetime import date
from pylanis import Lanis
lanis = Lanis(school_id="1234", username="vorname.nachname", password="dein-passwort")
# oder: Lanis.from_env() liest die LANIS_*-Umgebungsvariablen
for task in lanis.get_tasks():
print(task.subject_name, task.title, task.date)
plan = lanis.get_substitution_plan()
for sub in plan.substitutions:
print(sub.hours, sub.class_name, sub.subject, sub.substitute)
events = lanis.get_calendar(date(2026, 11, 1), date(2026, 11, 30))
- Die Methoden geben Dataclasses zurück (
Task,SubstitutionPlan,CalendarEvent,Timetableusw.), Datumswerte alsdate/datetime. - Die Anmeldung passiert beim ersten Aufruf, der sie braucht.
Lanis.get_schools()braucht keine. - Jede
Lanis-Instanz hat ihre eigene Session, mehrere Konten in einem Prozess sind möglich.
Fehler:
ConfigurationError: Die übergebenen Zugangsdaten sind unvollständig.SessionExpiredError: Die Session ist abgelaufen (nur bei Anmeldung per Session-Cookie) und wurde zurückgesetzt.
Kommandozeile
Der Befehl lanis gibt die Daten als JSON aus, mit --format markdown als lesbaren Text.
export LANIS_SCHOOL_ID=1234
export LANIS_USERNAME=vorname.nachname
export LANIS_PASSWORD=dein-passwort
lanis substitutions
lanis --format markdown tasks
lanis calendar --start 2026-11-01 --end 2026-11-30
lanis timetable | jq '.entries[] | select(.day == "Montag")'
Alle Befehle stehen in der Tabelle Verfügbare Daten. lanis --help und lanis <befehl> --help zeigen alle Optionen. Fehler werden als Error: … auf stderr ausgegeben, der Befehl endet dann mit Exit-Code 1.
Mit Docker
-e NAME ohne Wert übernimmt die Variable aus deiner Shell:
docker run --rm -e LANIS_SCHOOL_ID -e LANIS_USERNAME -e LANIS_PASSWORD udondan/lanis substitutions
Damit nicht jeder Aufruf eine neue Anmeldung braucht, speichert ein Volume die Session (siehe Anmeldung). Als Alias verhält sich das Image dann wie ein installiertes lanis:
alias lanis='docker run --rm -e LANIS_SCHOOL_ID -e LANIS_USERNAME -e LANIS_PASSWORD -e LANIS_DATA_DIR=/data -v lanis-data:/data udondan/lanis'
lanis --format markdown tasks
MCP-Server
lanis mcp startet einen MCP-Server über stdio. Damit kann ein KI-Assistent die Daten abfragen, und du fragst einfach:
- „Was steht heute im Vertretungsplan?"
- „Welche Hausaufgaben habe ich diese Woche?"
- „Zeig mir alle Termine im April."
- „Habe ich ungelesene Nachrichten?"
Claude Desktop
Öffne die Konfigurationsdatei von Claude Desktop:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Füge einen Eintrag unter mcpServers hinzu. Die Umgebungsvariablen entsprechen der Tabelle unter Anmeldung:
{
"mcpServers": {
"lanis": {
"command": "uvx",
"args": ["--from", "pylanis", "lanis", "mcp"],
"env": {
"LANIS_SCHOOL_ID": "1234",
"LANIS_USERNAME": "vorname.nachname",
"LANIS_PASSWORD": "dein-passwort"
}
}
}
}
Nach dem Speichern Claude Desktop neu starten.
Mit Docker statt uvx sieht der Eintrag so aus. -e NAME ohne Wert reicht die Variable aus env an den Container weiter:
{
"mcpServers": {
"lanis": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"LANIS_SCHOOL_ID",
"-e",
"LANIS_USERNAME",
"-e",
"LANIS_PASSWORD",
"udondan/lanis"
],
"env": {
"LANIS_SCHOOL_ID": "1234",
"LANIS_USERNAME": "vorname.nachname",
"LANIS_PASSWORD": "dein-passwort"
}
}
}
}
Docker MCP Toolkit
Mit dem Docker MCP Toolkit von Docker Desktop läuft der Server als Container hinter dem MCP Gateway. Der Gateway startet den Container bei Bedarf und reicht die Tools an die verbundenen Clients weiter. Die Zugangsdaten liegen dabei als Secrets in Docker Desktop statt im Klartext in der Client-Konfiguration.
Voraussetzung: Docker Desktop mit aktiviertem MCP Toolkit.
-
Die Server-Definition
docker-mcp.ymlherunterladen und zu einem Toolkit-Profil hinzufügen. Das Toolkit liest solche Dateien nur aus seinem Katalog-Verzeichnis:mkdir -p ~/.docker/mcp/catalogs curl -fsSL https://raw.githubusercontent.com/udondan/pylanis/main/docker-mcp.yml -o ~/.docker/mcp/catalogs/pylanis.yml # neues Profil "lanis" ... docker mcp profile create --name lanis --id lanis --server "file://$HOME/.docker/mcp/catalogs/pylanis.yml" # ... oder zu einem bestehenden Profil hinzufügen docker mcp profile server add default --server "file://$HOME/.docker/mcp/catalogs/pylanis.yml"
Das Profil hält das Image auf dem Stand, den es beim Hinzufügen hatte. Für ein Update
profile server adderneut ausführen. -
Zugangsdaten als Secrets hinterlegen (siehe Anmeldung):
docker mcp secret set lanis-mcp.school_id=1234 docker mcp secret set lanis-mcp.username=vorname.nachname docker mcp secret set lanis-mcp.password=dein-passwort
-
Einen Client mit dem Profil verbinden:
docker mcp client connect claude-desktop --profile lanis
Weitere Clients wie
claude-code,cursorodervscodezeigtdocker mcp client connect --help. Alternativ geht das in Docker Desktop unter MCP Toolkit.
docker mcp gateway run --profile lanis --dry-run --verbose prüft die Einrichtung, ohne einen Client zu starten. Am Ende sollte lanis-mcp: (15 tools) stehen.
Ausgabe
Die meisten Tools haben einen Parameter response_format: markdown (Standard, für Menschen lesbar) oder json (maschinenlesbar). Du kannst das Format einfach in deiner Frage angeben, z. B. „Zeig mir den Vertretungsplan als JSON."
Antworten sind auf 25.000 Zeichen begrenzt. Längere Ergebnisse werden gekürzt und mit einem Hinweis versehen. Grenze die Abfrage dann ein, z. B. mit einem kürzeren Zeitraum im Kalender.
Fehlerbehebung
Session abgelaufen
Betrifft nur die Anmeldung per Session-Cookie, mit Benutzername und Passwort meldet sich pylanis selbst neu an. Einen neuen Session-Cookie eintragen oder auf Benutzername und Passwort wechseln.
App an der Schule nicht verfügbar
Nicht alle Schulen haben alle Lanis-Module aktiviert. lanis available-apps (bzw. get_available_apps) zeigt, welche der unterstützten Apps freigeschaltet sind.
Kein Vertretungsplan
Den Vertretungsplan gibt es nur an Schultagen, nicht an Wochenenden und Feiertagen. Manche Schulen zeigen die App „Vertretungsplan" an, nutzen sie aber nicht. Dann meldet pylanis, dass keine Vertretungsdaten vorliegen.
Keine Termine gefunden
Prüfe den Zeitraum. start und end müssen im Format JJJJ-MM-TT angegeben werden.
Verbindungsfehler
Prüfe die Zugangsdaten (beim MCP-Server die Umgebungsvariablen in der Client-Konfiguration bzw. die Secrets im Docker MCP Toolkit) und ob du Zugang zum Schulportal Hessen hast (ggf. VPN oder Schulnetzwerk erforderlich).
Lizenz
pylanis steht unter der MIT-Lizenz.
Der Ordner src/pylanis/lanisapi/ basiert auf LanisAPI 0.4.1 von Dacjan Gapinski. Das Projekt wird nicht mehr weiterentwickelt; der Code wurde überarbeitet und wird hier gepflegt. LanisAPI steht ebenfalls unter der MIT-Lizenz, siehe src/pylanis/lanisapi/LICENSE.
Metadata
Release files for pylanis 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pylanis-1.1.0.tar.gz | 67.4 kB | With provenance | Details for pylanis-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pylanis-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for pylanis-1.1.0-py3-none-any.whl |
Total release size: 118.2 kB
Release files / pylanis-1.1.0.tar.gz
| Download URL | pylanis-1.1.0.tar.gz |
|---|---|
| Size | 67.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e3dceed34764e3fb5b642b2166d626c4acf70a145ceee1e3d57f0829b8b6da17
|
|
BLAKE2b-256 checksum How to use checksums |
e0a5cd99d7b6c6c67eb984c34dc6a8bb4ea78913e128d5ecda2d61cb0de2ba01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logRelease files / pylanis-1.1.0-py3-none-any.whl
| Download URL | pylanis-1.1.0-py3-none-any.whl |
|---|---|
| Size | 50.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9f3acc0904b7db347b13cb020163f1d1864e2f9337032a51dc33e9f9f74dbf2d
|
|
BLAKE2b-256 checksum How to use checksums |
6ee768344d2ab3b687c6c00a377f31ca6ee2ef3a1640b4479adc409979387643
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logSecurity for pylanis 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pylanis-1.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.