aria-mcp-affald-horsens
by kimhjort
README.md
# aria-mcp-affald-horsens
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for household waste collection schedules in **Horsens Kommune**. Built for [ARIA](https://github.com/kimhjort/aria) and shareable with the community.
Example output ARIA might give Kim:
> *i aften: rest/madaffald ud (tømmes mandag den 15. juni)*
> *næste papir/pap: tirsdag den 23. juni (om 10 dage)*
## Data Source
Data is fetched from **PerfectWaste** (`https://europe-west3-perfect-waste.cloudfunctions.net`), the backend powering Horsens Kommune's waste portal. The API is **unofficial and undocumented** — it was reverse-engineered from the portal and community Home Assistant integrations. There is no guarantee of stability; Horsens might migrate providers without notice.
The legacy `horsens.renoweb.dk` ASMX endpoint (`GetAffaldsplanMateriel_mitAffald`) is **MitID-gated** and cannot be used headlessly. Only address search on that endpoint is unauthenticated, but it is useless without schedule access. PerfectWaste is fully headless with no auth.
> **Best-effort only.** Always verify collection dates at [horsens.dk/affald](https://horsens.dk/affald).
## Install & Run
```bash
npx aria-mcp-affald-horsens
```
Or install globally:
```bash
npm install -g aria-mcp-affald-horsens
aria-mcp-affald-horsens
```
Requires Node.js 20 or later.
## Tools
### `find_address`
Search for a Horsens address and return PerfectWaste address candidates (id + display name).
**Parameters:**
| Name | Type | Required | Description |
|---|---|---|---|
| `query` | string | Yes | Address string to search (e.g. `"Vestergade 5"`, `"Søndergade 1, 8700 Horsens"`) |
**Returns:**
```json
{
"query": "Vestergade 5",
"candidates": [
{ "addressID": "39429", "displayName": "Vestergade 5, 8732 Hovedgård" },
{ "addressID": "47864", "displayName": "Vestergade 5, 8700 Horsens" }
]
}
```
---
### `next_collection`
Return the next upcoming collection date for each waste fraction at an address.
**Parameters:**
| Name | Type | Required | Description |
|---|---|---|---|
| `address` | string | Yes | Free-text address or raw PerfectWaste addressID (digits only) |
**Returns:**
```json
{
"addressID": "47864",
"addressDisplay": "Vestergade 5, 8700 Horsens",
"asOf": "2026-06-13T08:00",
"nextByFraction": [
{
"fractionName": "Rest - Mad",
"date": "2026-06-15T00:00:00.000Z",
"dateLocal": "2026-06-15",
"dateLabel": "mandag den 15. juni 2026",
"daysUntil": 2,
"putOutTonight": false
},
{
"fractionName": "Papir, pap og tekstilaffald",
"date": "2026-06-23T00:00:00.000Z",
"dateLocal": "2026-06-23",
"dateLabel": "tirsdag den 23. juni 2026",
"daysUntil": 10,
"putOutTonight": false
},
{
"fractionName": "Plast og drikkekarton - Glas og metal",
"date": "2026-06-26T00:00:00.000Z",
"dateLocal": "2026-06-26",
"dateLabel": "fredag den 26. juni 2026",
"daysUntil": 13,
"putOutTonight": false
}
],
"notice": "Data source: PerfectWaste (unofficial API, Horsens Kommune). ..."
}
```
`putOutTonight` is `true` when the collection is tomorrow — use it for reminders like *"i aften: rest/madaffald ud"*.
---
### `collection_calendar`
Return all upcoming collection events for the next N weeks.
**Parameters:**
| Name | Type | Required | Description |
|---|---|---|---|
| `address` | string | Yes | Free-text address or raw PerfectWaste addressID |
| `weeks` | number | No | Look-ahead in weeks (default 4, max 52) |
**Returns:** Same fields as `next_collection` events but as a flat chronological list covering the full window.
---
## Environment Variables
| Variable | Default | Description |
|---|---|---|
| `RENOWEB_HOST` | `https://europe-west3-perfect-waste.cloudfunctions.net` | Override the PerfectWaste base URL. Useful if another kommune uses the same backend at a different endpoint. |
| `RENOWEB_MUNICIPALITY` | `615` | Municipality code. `615` = Horsens. Other PerfectWaste kommuner may use different codes. |
The `RENOWEB_*` names are intentional — they keep the interface familiar and forward-compatible if a true RenoWeb headless path is discovered later.
## ARIA MCP Config
Add to your ARIA MCP config (`mcpServers` in ARIA credentials):
```json
{
"command": "npx",
"args": ["-y", "aria-mcp-affald-horsens"],
"env": {}
}
```
ARIA can then answer questions like:
- *"hvornår tømmes papir næste gang?"*
- *"hvad skal ud i aften?"*
- *"vis affaldskalender for de næste 4 uger på Vestergade 5"*
## Fragility Notes
- **API is undocumented.** PerfectWaste has no published SLA for this endpoint. It has been stable since at least early 2026, but could break without notice.
- **Municipality codes.** The `615` code for Horsens was discovered empirically. Other kommuner using PerfectWaste will have different codes.
- **Address coverage.** Some commercial/institutional addresses (e.g. Rådhustorvet 4) return empty collection data — the portal apparently only covers residential collection routes.
- **Calendar depth.** PerfectWaste typically returns ~3 months of data. The `weeks` parameter is capped client-side.
## Development
```bash
git clone https://github.com/kimhjort/aria-mcp-affald-horsens
cd aria-mcp-affald-horsens
npm install
npm run build
npm test
```
## License
MIT — see [LICENSE](LICENSE).
TDQS
A4.4/5.0
Scored across 3 tools
Disambiguation5/5
Each tool has a clear, distinct purpose: address resolution, next collection, and calendar of upcoming collections. No overlap.
Naming Consistency5/5
All tool names use consistent snake_case verb_noun pattern: find_address, next_collection, collection_calendar.
Tool Count5/5
Three tools are well-scoped for the domain of waste collection lookup in a single municipality—sufficient without being excessive.
Completeness5/5
The set covers address disambiguation, immediate next collection, and future planning via calendar. No obvious gaps.
Maintenance
ActivityMaintained
ResponsivenessSyncing