GDI Catalogue MCP
<p align="center">
<a href="https://jstaab.de/news/gdi-mcp/">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/logo-dark.svg">
<img alt="GDI Catalogue MCP" src="assets/logo-light.svg" width="480">
</picture>
</a>
</p>
<h3 align="center">Geodaten per Prompt — Deutschlands Geodatenkatalog für KI-Agenten</h3>
<p align="center">
<a href="README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-2563EB?style=for-the-badge"></a>
<a href="README.en.md"><img alt="English" src="https://img.shields.io/badge/English-30363D?style=for-the-badge"></a>
</p>
<p align="center">
<a href="https://de.wikipedia.org/wiki/Model_Context_Protocol"><img alt="MCP: stdio" src="https://img.shields.io/badge/MCP-stdio-2563EB?style=for-the-badge&labelColor=555555"></a>
<a href="https://docs.geonetwork-opensource.org/3.12/api/csw/"><img alt="CSW: 2.0.2" src="https://img.shields.io/badge/CSW-2.0.2-0891B2?style=for-the-badge&labelColor=555555"></a>
<a href="https://www.gdi-de.org/"><img alt="Zugriff: nur lesend" src="https://img.shields.io/badge/Zugriff-nur_lesend-16A34A?style=for-the-badge&labelColor=555555"></a>
<a href="https://opensource.org/license/mit"><img alt="Lizenz: MIT" src="https://img.shields.io/badge/Lizenz-MIT-6E7781?style=for-the-badge&labelColor=555555"></a>
</p>
<p align="center">
<a href="#installation">Installation</a> · <a href="#mcp-client-konfigurieren">Client</a> · <a href="#tools">Tools</a> · <a href="#endpunkt">Endpunkt</a> · <a href="#tests-und-einschränkungen">Tests</a> · <a href="#sicherheit-und-nutzungsbedingungen">Sicherheit</a> · <a href="https://jstaab.de/news/gdi-mcp/">Blog-Artikel ↗</a>
</p>
---
Kleiner, lesender MCP-Connector für **Geodatenkatalog.de / GDI-DE**. Nutzt ausschließlich **CSW 2.0.2** mit Dublin-Core-Ausgabe und das offizielle Python-MCP-SDK über **stdio**. Kein offizieller GDI-DE-/BKG-Dienst.
## Installation
Voraussetzungen: Python ≥3.11 und [uv](https://docs.astral.sh/uv/).
Repository klonen und im Projektverzeichnis ausführen:
```bash
uv sync --frozen
uv run --frozen python test_server.py
```
`uv.lock` enthält die aufgelösten Abhängigkeiten.
## MCP-Client konfigurieren
Im MCP-Client den Python-Interpreter und das Skript mit absoluten Pfaden registrieren:
```json
{
"mcpServers": {
"gdi-de": {
"command": "/absolute/path/gdi-geonetwork-mcp/.venv/bin/python",
"args": ["/absolute/path/gdi-geonetwork-mcp/server.py"]
}
}
}
```
Der Client startet den Prozess über stdio; kein Docker oder Port erforderlich. Bei Verschieben des Projekts Pfade aktualisieren.
Beispielprompt:
> Suche im GDI-DE-Katalog nach Lärm in Ingolstadt. Zeig mir anschließend die Metadaten und Ressourcenlinks eines Treffers.
## Tools
| Tool | Eingaben | Ausgabe |
|---|---|---|
| `search_records` | `query`, `limit` (1–50), `start` (ab 1) | Quelle, Trefferzahl, nächste Seite, Metadaten |
| `get_record` | `record_id` aus einem Treffer | Dublin-Core-Metadaten, Themen, Rechte, Ressourcenlinks, Metadaten-Bounding-Boxes |
`search_records` nutzt CSW `GetRecords`, `get_record` nutzt `GetRecordById`. `query` ist eine Wortsuche, keine rohe CQL-Abfrage. Wörter werden per AND und `AnyText LIKE` kombiniert; CQL-Wildcards `%` und `_` bleiben wirksam. `next_record=0` bedeutet Ende.
Ressourcenlinks werden **nicht** automatisch geöffnet. Ein Metadaten-Footprint beweist keine lokale Datenabdeckung. Keine Downloads, Kartenanalyse, räumliche Suchparameter, Schreibfunktionen, Uploads oder Harvesting.
## Endpunkt
Standard: `https://gdk.gdi-de.org/gdi-de/srv/ger/csw`.
Für einen anderen CSW-Katalog `CSW_URL` in der Prozessumgebung setzen (im obigen Client-Beispiel über `env`). Die URL wird ausschließlich vom Betreiber konfiguriert, nicht als Tool-Parameter angeboten. Andere Kataloge sind nicht getestet; CSW 2.0.2 und Dublin-Core-Ausgabe müssen unterstützt werden.
## Tests und Einschränkungen
Offline-Tests prüfen Eingabevalidierung, CQL-Escaping, Metadaten, Pagination, XML-Sicherheit und Antwortgrößenlimit.
```bash
uv run --frozen python test_server.py --live
```
`--live` startet einen echten MCP-Prozess und prüft Suche, Record-Abruf, Pagination und Toolfehler; Internet nötig. Timeouts oder andere Anbieterfehler werden nicht als Erfolg gewertet.
**Livetest bestanden:** GDI-DE-CSW-Suche „Lärm Ingolstadt“ mit 17 Treffern, Record-Abruf, Pagination und Toolfehler über MCP stdio geprüft. Frühere Tests liefen zeitweise in CSW-Suchtimeouts; die Verfügbarkeit hängt vom Anbieter ab. Es gibt keinen alternativen Suchpfad oder automatischen Fallback.
## Sicherheit und Nutzungsbedingungen
HTTP-Zeitlimit 30 Sekunden, maximal 5 MiB Antwort, keine automatischen Redirects oder Wiederholungen. Sichere XML-Verarbeitung ohne DTD/Entities. Katalogfehler und ungültige Eingaben erscheinen als MCP-Toolfehler. Keine Credentials erforderlich oder gespeichert; geschützte Kataloge werden nicht unterstützt.
GDI-DE stellt die Kataloginhalte [über standardisierte Schnittstellen zur freien Verfügung](https://www.gdi-de.org/praxis-projekte/servicefunktionen/geodatenkatalog-de). Daraus folgt keine pauschale Freigabe der verlinkten Geodaten. Für deren Nutzung gelten die jeweiligen Anbieterbedingungen; Quellenvermerke und rechtliche Hinweise beachten. Leere Rechtefelder sind keine Nutzungserlaubnis.
TDQS
Scored across 2 tools
search_records is for discovery via keywords and pagination, while get_record retrieves a specific record by its exact ID. The two purposes are clearly separated with no overlap, so an agent can easily choose the correct tool.
Both tools follow a consistent snake_case verb_noun pattern: search_records and get_record. The plural/singular noun difference reflects the operation (search many vs. get one) and does not break the pattern.
With only two tools, the surface feels thin for a CSW catalogue even though the two provided operations are focused. The count is borderline per the rubric for 1–2 tools, lacking additional conveniences like capabilities or spatial search.
The core read-only lifecycle of discovery (search) and retrieval by ID (get_record) is fully covered, including pagination hints. Minor gaps remain, such as no direct spatial/bbox search or get_capabilities operation, but agents can work around these using keyword search.