uba-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uba_mcp-0.1.0/.github/workflows/publish.yml +20 -0
- uba_mcp-0.1.0/.github/workflows/registry.yml +95 -0
- uba_mcp-0.1.0/.github/workflows/smoke.yml +21 -0
- uba_mcp-0.1.0/LICENSE +21 -0
- uba_mcp-0.1.0/PKG-INFO +92 -0
- uba_mcp-0.1.0/README-de.md +57 -0
- uba_mcp-0.1.0/README-fa.md +57 -0
- uba_mcp-0.1.0/README.md +80 -0
- uba_mcp-0.1.0/pyproject.toml +22 -0
- uba_mcp-0.1.0/server.json +1 -0
- uba_mcp-0.1.0/src/uba_mcp/__init__.py +1 -0
- uba_mcp-0.1.0/src/uba_mcp/domain.py +404 -0
- uba_mcp-0.1.0/src/uba_mcp/http.py +109 -0
- uba_mcp-0.1.0/src/uba_mcp/server.py +213 -0
- uba_mcp-0.1.0/tests/__init__.py +0 -0
- uba_mcp-0.1.0/tests/fixtures/airquality-debe010.json +740 -0
- uba_mcp-0.1.0/tests/fixtures/components.json +100 -0
- uba_mcp-0.1.0/tests/fixtures/meta.json +410 -0
- uba_mcp-0.1.0/tests/fixtures/stations.json +281 -0
- uba_mcp-0.1.0/tests/smoke_live.py +17 -0
- uba_mcp-0.1.0/tests/test_domain.py +186 -0
- uba_mcp-0.1.0/tests/test_live.py +77 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write # required for PyPI trusted publishing (OIDC)
|
|
12
|
+
contents: read
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: Publish to MCP Registry
|
|
2
|
+
|
|
3
|
+
# Official MCP Registry (registry.modelcontextprotocol.io) via GitHub OIDC.
|
|
4
|
+
# No secret, no interactive login: the runner's OIDC token proves ownership
|
|
5
|
+
# of the io.github.mohammad-abbasi-sh/* namespace.
|
|
6
|
+
# Refs: https://github.com/modelcontextprotocol/registry
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # required for OIDC -> MCP Registry
|
|
18
|
+
contents: read
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Sync server.json version to tag
|
|
23
|
+
# Only sync when running on a version tag (v*). On workflow_dispatch
|
|
24
|
+
# (ref = refs/heads/main) keep the version committed in server.json.
|
|
25
|
+
run: |
|
|
26
|
+
VER=""
|
|
27
|
+
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
|
|
28
|
+
TAG="${GITHUB_REF#refs/tags/}"
|
|
29
|
+
VER="${TAG#v}"
|
|
30
|
+
fi
|
|
31
|
+
if [ -n "$VER" ]; then
|
|
32
|
+
python3 - "$VER" << 'EOF'
|
|
33
|
+
import json, sys
|
|
34
|
+
ver = sys.argv[1]
|
|
35
|
+
d = json.load(open('server.json'))
|
|
36
|
+
d['version'] = ver
|
|
37
|
+
for pkg in d.get('packages', []):
|
|
38
|
+
pkg['version'] = ver
|
|
39
|
+
json.dump(d, open('server.json', 'w'), indent=2, ensure_ascii=False)
|
|
40
|
+
print('server.json version ->', ver)
|
|
41
|
+
EOF
|
|
42
|
+
else
|
|
43
|
+
echo "No version tag ($GITHUB_REF); keeping server.json version as-is"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
- name: Wait for PyPI
|
|
47
|
+
# The registry validates that the PyPI package + version exists,
|
|
48
|
+
# but the PyPI publish workflow runs in parallel with this one.
|
|
49
|
+
# Poll until the version appears instead of racing it: a 400 here
|
|
50
|
+
# used to fail silently under continue-on-error and left 40/43
|
|
51
|
+
# servers unlisted in the registry (2026-11-11).
|
|
52
|
+
run: |
|
|
53
|
+
python3 - << 'EOF'
|
|
54
|
+
import json, sys, time, urllib.request, urllib.error
|
|
55
|
+
d = json.load(open('server.json'))
|
|
56
|
+
pkg = d['packages'][0]
|
|
57
|
+
name = pkg.get('identifier') or pkg.get('name')
|
|
58
|
+
ver = pkg['version']
|
|
59
|
+
if not name:
|
|
60
|
+
print('ERROR: no package identifier/name in server.json')
|
|
61
|
+
sys.exit(1)
|
|
62
|
+
url = f'https://pypi.org/pypi/{name}/json'
|
|
63
|
+
for attempt in range(1, 21):
|
|
64
|
+
try:
|
|
65
|
+
with urllib.request.urlopen(url, timeout=30) as r:
|
|
66
|
+
data = json.load(r)
|
|
67
|
+
if ver in data.get('releases', {}):
|
|
68
|
+
print(f'PyPI {name}=={ver} is live (attempt {attempt})')
|
|
69
|
+
sys.exit(0)
|
|
70
|
+
except urllib.error.HTTPError as e:
|
|
71
|
+
print(f'attempt {attempt}: PyPI returned {e.code}')
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f'attempt {attempt}: {e}')
|
|
74
|
+
print(f'attempt {attempt}: {name}=={ver} not on PyPI yet, waiting 30s...')
|
|
75
|
+
time.sleep(30)
|
|
76
|
+
print(f'ERROR: {name}=={ver} did not appear on PyPI after 10 minutes')
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
EOF
|
|
79
|
+
|
|
80
|
+
- name: Install mcp-publisher
|
|
81
|
+
run: |
|
|
82
|
+
curl -sL "https://github.com/modelcontextprotocol/registry/releases/download/v1.8.7/mcp-publisher_linux_amd64.tar.gz" -o /tmp/mcp-publisher.tar.gz
|
|
83
|
+
tar -xzf /tmp/mcp-publisher.tar.gz -C /tmp
|
|
84
|
+
sudo mv /tmp/mcp-publisher /usr/local/bin/mcp-publisher
|
|
85
|
+
mcp-publisher --version
|
|
86
|
+
|
|
87
|
+
- name: Validate server.json
|
|
88
|
+
run: mcp-publisher validate server.json
|
|
89
|
+
|
|
90
|
+
- name: Publish to MCP Registry (OIDC)
|
|
91
|
+
# Failures must fail the run visibly: a silent publish failure
|
|
92
|
+
# once left 40/43 servers unlisted in the registry (2026-11-11).
|
|
93
|
+
run: |
|
|
94
|
+
mcp-publisher login github-oidc
|
|
95
|
+
mcp-publisher publish server.json
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Daily live smoke
|
|
2
|
+
|
|
3
|
+
# One fixed probe per day: catches fingerprint rot / bot-wall changes
|
|
4
|
+
# before users hit them. Fails visibly on 403/timeout.
|
|
5
|
+
on:
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: "0 6 * * *"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
smoke:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- name: Install
|
|
19
|
+
run: pip install -e .
|
|
20
|
+
- name: Smoke probe
|
|
21
|
+
run: python tests/smoke_live.py
|
uba_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohammad Abbasi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
uba_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: uba-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial read-only MCP server for UBA German air quality — hourly measurements and LQI from 400+ stations
|
|
5
|
+
Author: Mohammad Abbasi
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: httpx>=0.27
|
|
10
|
+
Requires-Dist: mcp<2
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# uba-mcp 🌬️
|
|
14
|
+
|
|
15
|
+
mcp-name: io.github.mohammad-abbasi-sh/uba-mcp
|
|
16
|
+
|
|
17
|
+
Unofficial **read-only** MCP server for **[UBA air quality](https://www.umweltbundesamt.de/en/data/air/air-data)** — the Umweltbundesamt (German Federal Environment Agency) Air Data API v4: hourly measurements from ~400 German stations (PM10, PM2.5, NO2, O3, SO2, CO, benzene …) since 2016, with the official UBA air-quality index (LQI). No key, no login.
|
|
18
|
+
|
|
19
|
+
> Built by Mohammad Abbasi as part of the "Germany MCP factory". Not affiliated with the Umweltbundesamt.
|
|
20
|
+
|
|
21
|
+
## For AI agents
|
|
22
|
+
|
|
23
|
+
Add to your MCP client config (stdio):
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"uba": {
|
|
29
|
+
"command": "uvx",
|
|
30
|
+
"args": ["uba-mcp==0.1.0"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or run locally: `python -m uba_mcp.server` (needs `mcp<2`, `httpx`).
|
|
37
|
+
|
|
38
|
+
## Tools
|
|
39
|
+
|
|
40
|
+
| Tool | Description |
|
|
41
|
+
|------|-------------|
|
|
42
|
+
| `uba_list_stations` | Measuring stations, filterable by city, state, type, area or name |
|
|
43
|
+
| `uba_station_detail` | One station: address, coordinates, type, data window, recent pollutants |
|
|
44
|
+
| `uba_current_air_quality` | Latest hourly values + LQI at a station (code, id or city name) |
|
|
45
|
+
| `uba_measurements` | Hourly values over a date range (max 31 days) + min/max/mean & daily means |
|
|
46
|
+
| `uba_list_components` | All 12 pollutants: code, symbol, unit, name |
|
|
47
|
+
| `uba_list_networks` | The 17 measuring networks (16 Länder + UBA) |
|
|
48
|
+
| `uba_health` | Reachability check (ok / blocked / error) — one polite request |
|
|
49
|
+
|
|
50
|
+
Example output (`uba_current_air_quality` / Berlin Neukölln, 2026-11-11 09:00 CET):
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{"station": {"code": "DEBE034", "name": "Berlin Neukölln", "city": "Berlin"},
|
|
54
|
+
"hour": {"start": "2026-11-11 09:00:00", "total_index": 2, "total_label": "moderate",
|
|
55
|
+
"values": [{"code": "PM2", "value": 17.0, "unit": "µg/m³", "label": "moderate"},
|
|
56
|
+
{"code": "PM10", "value": 23.0, "unit": "µg/m³", "label": "good"},
|
|
57
|
+
{"code": "O3", "value": 24.0, "unit": "µg/m³", "label": "very good"},
|
|
58
|
+
{"code": "NO2", "value": 15.0, "unit": "µg/m³", "label": "good"}]}}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Notes:
|
|
62
|
+
- Stations are found by code (`DEBE010` = Berlin Wedding), numeric id, or city name (first active station in that city).
|
|
63
|
+
- The `index` / `total_index` (0–4) and labels come from the API itself; they follow the UBA LQI, 2025 revision (hourly means, µg/m³):
|
|
64
|
+
|
|
65
|
+
| Class | NO2 | PM10 | PM2.5 | O3 | SO2 |
|
|
66
|
+
|-------|-----|------|-------|----|-----|
|
|
67
|
+
| 0 very good | 0–10 | 0–9 | 0–5 | 0–24 | 0–10 |
|
|
68
|
+
| 1 good | 11–30 | 10–27 | 6–15 | 25–72 | 11–30 |
|
|
69
|
+
| 2 moderate | 31–60 | 28–54 | 16–30 | 73–144 | 31–60 |
|
|
70
|
+
| 3 poor | 61–100 | 55–90 | 31–50 | 145–240 | 61–100 |
|
|
71
|
+
| 4 very poor | >100 | >90 | >50 | >240 | >100 |
|
|
72
|
+
|
|
73
|
+
- All times are CET/CEST as returned by the API. Data: UBA Air Data API v4 `umweltbundesamt.de/api/air_data/v4` — no key, no login, read-only.
|
|
74
|
+
|
|
75
|
+
## Development
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
python3 -m venv .venv && .venv/bin/pip install "mcp<2" httpx pytest
|
|
79
|
+
.venv/bin/pip install -e .
|
|
80
|
+
.venv/bin/python -m pytest tests/ -q
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- `tests/test_domain.py` — offline, parses real captured API fixtures
|
|
84
|
+
- `tests/test_live.py` — 7 cautious live requests against the UBA API
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
Built by [Mohammad Abbasi](https://github.com/mohammad-abbasi-sh) — [Almanibama](https://almanibama.ir) · [mabbasi.ir](https://mabbasi.ir)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# uba-mcp 🌬️
|
|
2
|
+
|
|
3
|
+
mcp-name: io.github.mohammad-abbasi-sh/uba-mcp
|
|
4
|
+
|
|
5
|
+
Inoffizieller **nur lesender** MCP-Server für **[UBA-Luftqualität](https://www.umweltbundesamt.de/en/data/air/air-data)** — die Air-Data-API v4 des Umweltbundesamtes: stündliche Messwerte von rund 400 deutschen Messstationen (PM10, PM2,5, NO2, O3, SO2, CO, Benzol …) seit 2016, mit dem amtlichen Luftqualitätsindex (LQI) des UBA. Kein Schlüssel, keine Anmeldung.
|
|
6
|
+
|
|
7
|
+
> Gebaut von Mohammad Abbasi als Teil der "Germany MCP factory". Nicht mit dem Umweltbundesamt verbunden.
|
|
8
|
+
|
|
9
|
+
## Für KI-Agenten
|
|
10
|
+
|
|
11
|
+
Zur MCP-Client-Konfiguration hinzufügen (stdio):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"uba": {
|
|
17
|
+
"command": "uvx",
|
|
18
|
+
"args": ["uba-mcp==0.1.0"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Oder lokal starten: `python -m uba_mcp.server` (benötigt `mcp<2`, `httpx`).
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
| Tool | Beschreibung |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| `uba_list_stations` | Messstationen, filterbar nach Stadt, Bundesland, Typ, Gebiet oder Name |
|
|
31
|
+
| `uba_station_detail` | Eine Station: Adresse, Koordinaten, Typ, Datenzeitraum, aktuelle Schadstoffe |
|
|
32
|
+
| `uba_current_air_quality` | Aktuelle Stundenwerte + LQI an einer Station (Code, ID oder Stadtname) |
|
|
33
|
+
| `uba_measurements` | Stundenwerte über einen Zeitraum (max. 31 Tage) + Min/Max/Mittel & Tagesmittel |
|
|
34
|
+
| `uba_list_components` | Alle 12 Schadstoffe: Code, Symbol, Einheit, Name |
|
|
35
|
+
| `uba_list_networks` | Die 17 Messnetze (16 Bundesländer + UBA) |
|
|
36
|
+
| `uba_health` | Erreichbarkeitsprüfung (ok / blocked / error) — eine höfliche Anfrage |
|
|
37
|
+
|
|
38
|
+
Hinweise:
|
|
39
|
+
- Stationen werden über Code (`DEBE010` = Berlin Wedding), numerische ID oder Stadtname gefunden (erste aktive Station der Stadt).
|
|
40
|
+
- `index` / `total_index` (0–4) und Labels kommen direkt aus der API; sie folgen dem UBA-LQI, Revision 2025 (Stundenmittelwerte, µg/m³): sehr gut / gut / mäßig / schlecht / sehr schlecht.
|
|
41
|
+
- Alle Zeiten sind MEZ/MESZ, wie von der API geliefert. Daten: UBA Air Data API v4 — kein Schlüssel, keine Anmeldung, nur lesend.
|
|
42
|
+
|
|
43
|
+
## Entwicklung
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python3 -m venv .venv && .venv/bin/pip install "mcp<2" httpx pytest
|
|
47
|
+
.venv/bin/pip install -e .
|
|
48
|
+
.venv/bin/python -m pytest tests/ -q
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Lizenz
|
|
52
|
+
|
|
53
|
+
MIT
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
Built by [Mohammad Abbasi](https://github.com/mohammad-abbasi-sh) — [Almanibama](https://almanibama.ir) · [mabbasi.ir](https://mabbasi.ir)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# uba-mcp 🌬️
|
|
2
|
+
|
|
3
|
+
mcp-name: io.github.mohammad-abbasi-sh/uba-mcp
|
|
4
|
+
|
|
5
|
+
سرور MCP غیررسمی و **فقطخواندنی** برای **[کیفیت هوای UBA](https://www.umweltbundesamt.de/en/data/air/air-data)** — API نسخهٔ ۴ دادههای هوای آژانس فدرال محیط زیست آلمان (Umweltbundesamt): اندازهگیریهای ساعتی از حدود ۴۰۰ ایستگاه آلمان (PM10، PM2.5، NO2، O3، SO2، CO، بنزن و…) از سال ۲۰۱۶، همراه با شاخص رسمی کیفیت هوا (LQI) از UBA. بدون کلید، بدون ورود.
|
|
6
|
+
|
|
7
|
+
> ساختهٔ محمد عباسی، بخشی از «کارخانهٔ MCP آلمان». وابسته به Umweltbundesamt نیست.
|
|
8
|
+
|
|
9
|
+
## برای ایجنتهای هوش مصنوعی
|
|
10
|
+
|
|
11
|
+
به پیکربندی MCP کلاینت اضافه کنید (stdio):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"uba": {
|
|
17
|
+
"command": "uvx",
|
|
18
|
+
"args": ["uba-mcp==0.1.0"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
یا بهصورت محلی اجرا کنید: `python -m uba_mcp.server` (نیازمند `mcp<2` و `httpx`).
|
|
25
|
+
|
|
26
|
+
## ابزارها
|
|
27
|
+
|
|
28
|
+
| ابزار | توضیح |
|
|
29
|
+
|------|-------|
|
|
30
|
+
| `uba_list_stations` | ایستگاههای اندازهگیری، قابل فیلتر بر اساس شهر، ایالت، نوع، منطقه یا نام |
|
|
31
|
+
| `uba_station_detail` | یک ایستگاه: آدرس، مختصات، نوع، بازهٔ دادهها، آلایندههای اخیر |
|
|
32
|
+
| `uba_current_air_quality` | آخرین مقادیر ساعتی + شاخص LQI در یک ایستگاه (کد، شناسه یا نام شهر) |
|
|
33
|
+
| `uba_measurements` | مقادیر ساعتی در یک بازه (حداکثر ۳۱ روز) + کمینه/بیشینه/میانگین و میانگین روزانه |
|
|
34
|
+
| `uba_list_components` | هر ۱۲ آلاینده: کد، نماد، واحد، نام |
|
|
35
|
+
| `uba_list_networks` | ۱۷ شبکهٔ اندازهگیری (۱۶ ایالت + UBA) |
|
|
36
|
+
| `uba_health` | بررسی دسترسپذیری (ok / blocked / error) — یک درخواست مؤدبانه |
|
|
37
|
+
|
|
38
|
+
نکتهها:
|
|
39
|
+
- ایستگاهها با کد (`DEBE010` = برلین ودینگ)، شناسهٔ عددی یا نام شهر پیدا میشوند (اولین ایستگاه فعال آن شهر).
|
|
40
|
+
- `index` / `total_index` (۰ تا ۴) و برچسبها مستقیم از API میآیند و از شاخص LQI بازبینیشدهٔ ۲۰۲۵ پیروی میکنند: بسیار خوب / خوب / متوسط / بد / بسیار بد.
|
|
41
|
+
- همهٔ زمانها CET/CEST هستند، همانطور که API برمیگرداند. دادهها: UBA Air Data API v4 — بدون کلید، بدون ورود، فقطخواندنی.
|
|
42
|
+
|
|
43
|
+
## توسعه
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
python3 -m venv .venv && .venv/bin/pip install "mcp<2" httpx pytest
|
|
47
|
+
.venv/bin/pip install -e .
|
|
48
|
+
.venv/bin/python -m pytest tests/ -q
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## لایسنس
|
|
52
|
+
|
|
53
|
+
MIT
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
Built by [Mohammad Abbasi](https://github.com/mohammad-abbasi-sh) — [Almanibama](https://almanibama.ir) · [mabbasi.ir](https://mabbasi.ir)
|
uba_mcp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# uba-mcp 🌬️
|
|
2
|
+
|
|
3
|
+
mcp-name: io.github.mohammad-abbasi-sh/uba-mcp
|
|
4
|
+
|
|
5
|
+
Unofficial **read-only** MCP server for **[UBA air quality](https://www.umweltbundesamt.de/en/data/air/air-data)** — the Umweltbundesamt (German Federal Environment Agency) Air Data API v4: hourly measurements from ~400 German stations (PM10, PM2.5, NO2, O3, SO2, CO, benzene …) since 2016, with the official UBA air-quality index (LQI). No key, no login.
|
|
6
|
+
|
|
7
|
+
> Built by Mohammad Abbasi as part of the "Germany MCP factory". Not affiliated with the Umweltbundesamt.
|
|
8
|
+
|
|
9
|
+
## For AI agents
|
|
10
|
+
|
|
11
|
+
Add to your MCP client config (stdio):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"uba": {
|
|
17
|
+
"command": "uvx",
|
|
18
|
+
"args": ["uba-mcp==0.1.0"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or run locally: `python -m uba_mcp.server` (needs `mcp<2`, `httpx`).
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
| Tool | Description |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| `uba_list_stations` | Measuring stations, filterable by city, state, type, area or name |
|
|
31
|
+
| `uba_station_detail` | One station: address, coordinates, type, data window, recent pollutants |
|
|
32
|
+
| `uba_current_air_quality` | Latest hourly values + LQI at a station (code, id or city name) |
|
|
33
|
+
| `uba_measurements` | Hourly values over a date range (max 31 days) + min/max/mean & daily means |
|
|
34
|
+
| `uba_list_components` | All 12 pollutants: code, symbol, unit, name |
|
|
35
|
+
| `uba_list_networks` | The 17 measuring networks (16 Länder + UBA) |
|
|
36
|
+
| `uba_health` | Reachability check (ok / blocked / error) — one polite request |
|
|
37
|
+
|
|
38
|
+
Example output (`uba_current_air_quality` / Berlin Neukölln, 2026-11-11 09:00 CET):
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{"station": {"code": "DEBE034", "name": "Berlin Neukölln", "city": "Berlin"},
|
|
42
|
+
"hour": {"start": "2026-11-11 09:00:00", "total_index": 2, "total_label": "moderate",
|
|
43
|
+
"values": [{"code": "PM2", "value": 17.0, "unit": "µg/m³", "label": "moderate"},
|
|
44
|
+
{"code": "PM10", "value": 23.0, "unit": "µg/m³", "label": "good"},
|
|
45
|
+
{"code": "O3", "value": 24.0, "unit": "µg/m³", "label": "very good"},
|
|
46
|
+
{"code": "NO2", "value": 15.0, "unit": "µg/m³", "label": "good"}]}}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Notes:
|
|
50
|
+
- Stations are found by code (`DEBE010` = Berlin Wedding), numeric id, or city name (first active station in that city).
|
|
51
|
+
- The `index` / `total_index` (0–4) and labels come from the API itself; they follow the UBA LQI, 2025 revision (hourly means, µg/m³):
|
|
52
|
+
|
|
53
|
+
| Class | NO2 | PM10 | PM2.5 | O3 | SO2 |
|
|
54
|
+
|-------|-----|------|-------|----|-----|
|
|
55
|
+
| 0 very good | 0–10 | 0–9 | 0–5 | 0–24 | 0–10 |
|
|
56
|
+
| 1 good | 11–30 | 10–27 | 6–15 | 25–72 | 11–30 |
|
|
57
|
+
| 2 moderate | 31–60 | 28–54 | 16–30 | 73–144 | 31–60 |
|
|
58
|
+
| 3 poor | 61–100 | 55–90 | 31–50 | 145–240 | 61–100 |
|
|
59
|
+
| 4 very poor | >100 | >90 | >50 | >240 | >100 |
|
|
60
|
+
|
|
61
|
+
- All times are CET/CEST as returned by the API. Data: UBA Air Data API v4 `umweltbundesamt.de/api/air_data/v4` — no key, no login, read-only.
|
|
62
|
+
|
|
63
|
+
## Development
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python3 -m venv .venv && .venv/bin/pip install "mcp<2" httpx pytest
|
|
67
|
+
.venv/bin/pip install -e .
|
|
68
|
+
.venv/bin/python -m pytest tests/ -q
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- `tests/test_domain.py` — offline, parses real captured API fixtures
|
|
72
|
+
- `tests/test_live.py` — 7 cautious live requests against the UBA API
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
Built by [Mohammad Abbasi](https://github.com/mohammad-abbasi-sh) — [Almanibama](https://almanibama.ir) · [mabbasi.ir](https://mabbasi.ir)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "uba-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Unofficial read-only MCP server for UBA German air quality — hourly measurements and LQI from 400+ stations"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mcp<2",
|
|
14
|
+
"httpx>=0.27",
|
|
15
|
+
]
|
|
16
|
+
authors = [{ name = "Mohammad Abbasi" }]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
uba-mcp = "uba_mcp.server:main"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["src/uba_mcp"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","description":"Unofficial read-only MCP server for German air quality (UBA) — hourly values + LQI, 400 stations.","name":"io.github.mohammad-abbasi-sh/uba-mcp","packages":[{"identifier":"uba-mcp","registryBaseUrl":"https://pypi.org","registryType":"pypi","transport":{"type":"stdio"},"version":"0.1.0"}],"repository":{"source":"github","url":"https://github.com/mohammad-abbasi-sh/uba-mcp"},"title":"UBA Air Quality","version":"0.1.0","websiteUrl":"https://github.com/mohammad-abbasi-sh/uba-mcp"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""uba_mcp package — unofficial read-only MCP access to UBA air data."""
|