deen
Alle Projekte
2026Konzept, Umsetzung, Betrieb

Abfall MCP

Abfuhrtermine aus 995 Trägerportalen, als MCP-Server

abfall-mcp.alpaycelik.dev

Überblick

Abfall ist in Deutschland kommunal organisiert: rund 400 Entsorgungsträger betreiben jeweils ihr eigenes Portal, eine bundesweite API gibt es nicht. Der Server nimmt eine Adresse, findet über Nominatim die Kommune, darüber den zuständigen Träger unter 995 aus 150 Quellmodulen, und holt die Termine aus dessen Portal. Die eigentliche Arbeit steckt nicht in den Terminen, sondern in dem Schritt davor: in Home Assistant klickt ein Mensch seinen Träger einmal von Hand zusammen, ein MCP-Server muss das allein hinbekommen - und wenn er es nicht sicher hinbekommt, nachfragen statt raten.

Das Problem

„Wann kommt die Biotonne" ist für einen Assistenten keine Frage über Termine, sondern eine über Zuständigkeit. Es gibt keinen bundesweiten Endpunkt, sondern rund 400 Träger auf einer Handvoll Portal-Plattformen - Abfall.IO, AbfallNavi, Jumomind, AWIDO, C-Trace, Müllmax - und daneben viele, die nur eine ICS-Datei ausliefern. Die Termine selbst muss niemand neu erschließen: das Projekt `hacs_waste_collection_schedule` pflegt über 950 Quellmodule dafür, MIT-lizenziert. Es ist hier als Submodul eingebunden, nicht kopiert. Was es nicht löst, ist der Schritt davor. In Home Assistant sitzt ein Mensch davor und klickt seinen Träger samt dessen internen Parametern einmal zusammen; ein MCP-Server bekommt eine Adresse in Prosa und sonst nichts. Und der Fehlerfall ist unangenehm leise. Wer die Kommune falsch rät, liefert den Kalender der Nachbargemeinde: eine falsche Antwort, die wie eine richtige aussieht, in einer Oberfläche, in der niemand eine Quellenangabe erwartet.

Randbedingungen

  • Kein bundesweiter Endpunkt: rund 400 Träger, jeder mit eigenem Portal
  • Nominatim erlaubt eine Anfrage pro Sekunde, und jede Abfrage belastet fremde Portale
  • Manche Portale verlangen interne IDs, die in keiner Adresse stehen
  • Tools und Antworten auf Deutsch, weil Domäne und Nutzer es sind

Entscheidungen

Zurückfragen statt raten

`status: "rueckfrage"` mit der konkreten Liste der Möglichkeiten

Die wahrscheinlichste Kommune nehmen und Termine liefern

Zwei Gemeinden können denselben Straßennamen führen, und die Portale kennen Schreibweisen, die in keiner Adresse stehen. Rät der Server, liefert er einen vollständig plausiblen Kalender der Nachbargemeinde, und der Fehler fällt frühestens auf, wenn die Tonne stehen bleibt. Eine Rückfrage kostet einen Satz und ist an der Stelle billiger als jede Korrektur danach. Das Prinzip steht auch in CONTRIBUTING.md, weil es sonst beim nächsten Resolver wieder zur Debatte steht.

Die Datenquelle einbinden, nicht nachbauen

`hacs_waste_collection_schedule` als Submodul, angesprochen über eine Brücke

150 Portal-Anbindungen selbst schreiben oder das Projekt forken

Über 950 gepflegte Quellmodule nachzubauen wäre ein zweites Projekt, das schlechter altert als das Original - Portale ändern sich, und wer forkt, pflegt die Änderungen allein. Der interessante Teil ist ohnehin die Auflösung davor. Die Anbindung hat dafür eine Eigenheit: das Paket wird bewusst registriert statt auf den `sys.path` gelegt, weil im Elternverzeichnis eine `calendar.py` liegt, die sonst die Standardbibliothek verdeckt. Solche Fallen findet man nur, wenn man fremden Code einbindet, statt ihn zu kopieren.

Nicht auf PyPI

Der Server läuft aus dem Checkout, mit `uv sync`

Ein Wheel veröffentlichen, wie man es von einem Python-Paket erwartet

Der Server braucht die Datenquelle unter `vendor/` und die Registry unter `data/`, beide relativ zum Projektverzeichnis aufgelöst. Ein Wheel würde sauber installieren und danach nicht funktionieren, und das ist der schlechteste aller Zustände: der Fehler tritt erst beim ersten Aufruf auf, und zwar bei jemandem, der der Installation geglaubt hat. Lieber ein Installationsweg, der aussieht wie das, was er ist.

Die Adressdialoge der Portale nachbauen

Eigene Auflösung für Abfall.IO (41 Träger), Hamburg und die BSR

Diese Träger auslassen oder die internen IDs vom Nutzer verlangen

Diese Portale verlangen Werte wie `f_id_kommune` oder `hnId`, die sich aus einer Adresse nicht ableiten lassen und die kein Mensch zur Hand hat. Wer sie erfragt, verschiebt die Arbeit auf den, der die Antwort wollte. Der Nachbau kostet einen Resolver pro Portalfamilie und deckt mit dreien einen großen Teil ab. Der Hamburger Assistent des Ursprungsprojekts ist inzwischen veraltet, weil das Portal sein Formular auf eine JavaScript-Komponente umgestellt hat; deren Adress-Endpunkt wird hier aus der Seite gelesen. Das ist der Teil, den man nachziehen muss, und genau deshalb liegt er in einer eigenen Datei.

Die Abdeckung messen und hinschreiben

21 echte Adressen gegen die echten Portale, Ergebnis im README

„Deckt alle deutschen Städte ab" - was für die Trägerliste sogar stimmt

Die Trägerliste deckt das Land ab, die vollautomatische Auflösung aus einer nackten Adresse nicht. 48 % liefern direkt Termine, 14 % enden in einer Rückfrage, bei 38 % kommt nichts zurück. Diese Zahl macht das Projekt angreifbar und ist trotzdem die nützlichere Angabe: Sie sagt einem Nutzer vorher, was ihn erwartet, und mir, woran ich als Nächstes arbeite. Die offenen Fälle stehen namentlich daneben - `standort` in Dresden, `idHouseNumber` in Leipzig, `streetnr` in Stuttgart, abweichende Schreibweisen in Erfurt und Kiel, und Saarbrücken, das HTML statt ICS zurückgibt.

Gebaut

  • 995 Träger aus 150 Quellmodulen, als vorgebaute Registry statt 150 Imports beim Start
  • Fragt zurück statt zu raten: eine falsch geratene Stadt liefert den Kalender der Nachbargemeinde
  • Adressdialoge nachgebaut, wo Portale interne IDs verlangen: Abfall.IO (41 Träger), Hamburg, BSR
  • Gemessene Abdeckung über 21 echte Adressen: 48 % Termine, 14 % Rückfrage, 38 % nichts