feat(skills): add marktguru supermarket offer and price comparison skill

Introduce the marktguru agent skill and MCP integration for searching supermarket deals, comparing product prices, and querying supported retail chains:
- Add Marktguru API client and MCP server script
- Add skill definition (SKILL.md) and supported supermarkets reference
- Add test suite covering Marktguru API integration and offer queries
This commit is contained in:
Moritz Graf
2026-10-05 21:20:16 +02:00
parent c3c7a4c8cf
commit 9d890a290f
7 changed files with 1312 additions and 0 deletions
+142
View File
@@ -0,0 +1,142 @@
---
name: marktguru
license: Apache-2.0
description: Query weekly supermarket offers, flyer discounts, and price comparisons across German supermarkets (ALDI Süd, ALDI Nord, Lidl, EDEKA, REWE, Kaufland, PENNY, Netto, dm, ROSSMANN, etc.) via the Marktguru API and local MCP server. Use when the user asks to check supermarket discounts, find deals in brochures/prospekte, compare grocery prices for a postal code (PLZ), or create shopping lists from current promotions without needing fragile PDF OCR.
---
# Marktguru Supermarket Offers & MCP Server
> Query live promotional flyers and circular offers from German supermarkets and drugstores without brittle PDF scraping or layout OCR.
This skill is inspired by and expands upon the Home Assistant integration pattern (`thorschtn/ha-marktguru`), leveraging Marktguru's backend API (`api.marktguru.de`) to retrieve structured deal data for any German postal code.
---
## Supported Supermarkets & Retailers
Marktguru covers **over 450 retail chains** across Germany. The primary supported chains are:
* **Discounter**:
* **ALDI SÜD** (`127153`) & **ALDI NORD** (`127139`)
* **Lidl** (`126679`)
* **PENNY** (`126765`)
* **Netto Marken-Discount** (`126735`) & **Netto (mit Hund)** (`126734`)
* **NORMA** (`126745`)
* **Supermärkte & Vollsortimenter**:
* **EDEKA** (`127093`) & **E center** (`126699`) + regionale Kaufleute (Simmel, Zurheide, etc.)
* **REWE** (`126802`) & **REWE Center** (`126804`)
* **nahkauf** (`137320`), **HIT** (`126598`), **tegut** (`126866`)
* **Großfläche / Hypermarket**:
* **Kaufland** (`126654`)
* **Globus** (`127177`)
* **Drogerien & Reform**:
* **dm-drogerie markt** (`127057`)
* **ROSSMANN** (`126811`)
* **Müller Drogeriemarkt** (`126720`)
Full details and ID mappings are documented in [`references/supermarkets.md`](references/supermarkets.md).
---
## Components
The skill provides two primary components:
1. **CLI & Python Client (`scripts/marktguru_client.py`)**: Zero external dependencies (uses standard library `urllib` and `json`).
2. **MCP Server (`scripts/marktguru_mcp.py`)**: Standard JSON-RPC 2.0 stdio server providing AI tools for search, comparison, and catalog retrieval.
---
## 1. CLI Usage
Run directly with standard `python3` (uses default postal code **`93059` Regensburg** if `--zip` is omitted):
### A. Search for Deals
```bash
# Search for butter in Regensburg (93059 default) across Aldi, Lidl, and Edeka
python3 scripts/marktguru_client.py search "Butter" --supermarket "Aldi,Lidl,Edeka"
# Search for coffee with raw JSON output
python3 scripts/marktguru_client.py search "Kaffee" --json
```
### B. Price Comparison (Sorted Ascending)
```bash
# Compare chocolate prices across all supermarkets in 93059
python3 scripts/marktguru_client.py compare "Schokolade"
# Compare beer prices between Lidl and Rewe in another postal code (e.g. 80331)
python3 scripts/marktguru_client.py compare "Bier" --zip 80331 --supermarket "Lidl,Rewe"
```
### C. List Supported Chains
```bash
python3 scripts/marktguru_client.py supermarkets
```
---
## 2. Model Context Protocol (MCP) Integration
The MCP server exposes three tools to any MCP-compatible AI agent:
* `search_supermarket_offers(query, zip_code="93059", supermarkets=None, limit=20)`
* `compare_supermarket_prices(query, zip_code="93059", supermarkets=None)`
* `list_supported_supermarkets()`
### MCP Server Configuration (`mcp_config.json`)
To enable the server in Antigravity or other MCP hosts:
```json
{
"mcpServers": {
"marktguru": {
"command": "python3",
"args": [
"/Users/moritz/src/infrapuzzle/.agents/skills/marktguru/scripts/marktguru_mcp.py"
]
}
}
}
```
---
## 3. Python Integration
You can import the module directly in Python scripts or agent sidecars:
```python
import sys
sys.path.append("/Users/moritz/src/infrapuzzle/.agents/skills/marktguru/scripts")
from marktguru_client import search_offers, compare_prices, DEFAULT_ZIP_CODE
# Search deals (defaults to 93059)
results = search_offers("Kaffee", supermarkets=["Aldi", "Lidl"])
for offer in results["offers"]:
print(f"[{offer['supermarket']}] {offer['product_name'] or offer['description']}: {offer['price']} €")
# Compare prices
comparison = compare_prices("Milch")
cheapest = comparison["cheapest_offer"]
print(f"Cheapest milk: {cheapest['price']} € at {cheapest['supermarket']}")
```
---
## Data Extracted Per Offer
Each item returned from the Marktguru API includes:
* `id`: Internal Marktguru offer ID.
* `supermarket`: Retailer name (e.g. "ALDI SÜD", "Lidl", "EDEKA").
* `product_name`: Generic product name (e.g. "Butter", "Filterkaffee").
* `brand`: Brand name (e.g. "Kerrygold", "Melitta", "Milka").
* `description`: Promotional description / pack size (e.g. "je 250g Packung").
* `price`: Promotional sale price in Euros (€).
* `old_price`: Regular price or crossed-out price (UVP).
* `discount_percent`: Calculated percentage savings (e.g. 28%).
* `reference_price`: Unit price (e.g. 5.16 € / kg).
* `loyalty_app_required`: Boolean flag indicating if a digital store app (Lidl Plus, Edeka App, Penny App) is required to receive the discount.
* `valid_from` & `valid_to`: Start and end dates of the promotion.
* `image_url`: High-resolution product image hosted on CDN.