Waste collection in Germany is organised municipally: roughly 400 authorities each run their own portal, and there is no nationwide API. The server takes an address, resolves the municipality through Nominatim, finds the responsible authority among 995 drawn from 150 source modules, and pulls the dates from that authority's portal. The work is not in the dates, it is in the step before: in Home Assistant a human clicks their authority together once by hand, and an MCP server has to manage it alone - or ask, when it cannot manage it with certainty.
The problem
"When is the organic waste collected" is not a question about dates for an assistant, it is a question about jurisdiction. There is no nationwide endpoint, there are roughly 400 authorities on a handful of portal platforms - Abfall.IO, AbfallNavi, Jumomind, AWIDO, C-Trace, Müllmax - and alongside them many that only publish an ICS file.
Nobody needs to rediscover the dates themselves: the `hacs_waste_collection_schedule` project maintains over 950 source modules for exactly that, under MIT. It is wired in here as a submodule rather than copied. What it does not solve is the step before. In Home Assistant a human sits in front of it and clicks their authority and its internal parameters together once; an MCP server gets an address in prose and nothing else.
And the failure mode is uncomfortably quiet. Guess the municipality wrong and you return the neighbouring one's calendar: a wrong answer that looks like a right one, in an interface where nobody expects a citation.
Constraints
No nationwide endpoint: roughly 400 authorities, each with its own portal
Nominatim allows one request per second, and every query loads someone else's portal
Some portals require internal IDs that appear in no address
Tool names and responses in German, because the domain and the users are
Decisions
Ask back instead of guessing
`status: "rueckfrage"` together with the concrete list of options
Taking the most likely municipality and returning dates
Two municipalities can share a street name, and the portals know spellings that appear in no address. If the server guesses, it returns an entirely plausible calendar for the neighbouring municipality, and the mistake surfaces at the earliest when the bin stays full. A follow-up question costs one sentence and is cheaper there than any correction afterwards. The principle is written into CONTRIBUTING.md as well, or it would be up for debate again at the next resolver.
Wire in the data source, do not rebuild it
`hacs_waste_collection_schedule` as a submodule, reached through a bridge module
Writing 150 portal integrations myself, or forking the project
Rebuilding over 950 maintained source modules would be a second project that ages worse than the original: portals change, and whoever forks maintains those changes alone. The interesting part is the resolution in front of it anyway. The bridge has one quirk for that: the package is deliberately registered rather than put on `sys.path`, because its parent directory holds a `calendar.py` that would otherwise shadow the standard library. You only find traps like that by wiring foreign code in instead of copying it.
Not on PyPI
The server runs from a checkout, with `uv sync`
Publishing a wheel, the way a Python package is expected to ship
The server needs the data source under `vendor/` and the registry under `data/`, both resolved relative to the project root. A wheel would install cleanly and then not work, which is the worst of all states: the error shows up at the first call, to someone who trusted the install. Better an installation path that looks like what it is.
Reimplement the portals' address dialogs
My own lookup for Abfall.IO (41 authorities), Hamburg and Berlin's BSR
Leaving those authorities out, or asking the user for the internal IDs
These portals require values like `f_id_kommune` or `hnId` that cannot be derived from an address and that no human has to hand. Asking for them moves the work back to the person who wanted the answer. Reimplementing costs one resolver per portal family, and three of them cover a large share. The upstream project's Hamburg wizard is stale by now because the portal moved its form to a JavaScript component; its address endpoint is read out of the page here instead. That is the part that needs maintaining, which is exactly why it sits in a file of its own.
Measure the coverage and publish it
21 real addresses against the real portals, the result in the README
"Covers every German city", which is even true of the authority list
The authority list covers the country; fully automatic resolution from a bare address does not. 48% return dates directly, 14% end in a follow-up question, and 38% return nothing. That number makes the project easy to attack and is still the more useful thing to state: it tells a user in advance what to expect, and tells me what to work on next. The open cases are named beside it: `standort` in Dresden, `idHouseNumber` in Leipzig, `streetnr` in Stuttgart, diverging spellings in Erfurt and Kiel, and Saarbrücken, which returns HTML instead of ICS.
What I built
995 authorities from 150 source modules, prebuilt into a registry instead of 150 imports at startup
Asks instead of guessing: a wrongly guessed town returns the neighbouring municipality's calendar
Portal address dialogs reimplemented where internal IDs are required: Abfall.IO (41 authorities), Hamburg, BSR
Coverage measured over 21 real addresses: 48% dates, 14% a follow-up question, 38% nothing