dutch-supermarkets-mcp
by thijserven
README.md
# Dutch Supermarkets MCP
TypeScript MCP server for Dutch supermarket and drugstore prices, promotions, shopping lists, meal planning, price alerts, routes, and budgets.
## MCP tools
| Tool | Purpose |
| ------------------------ | --------------------------------------------------- |
| `search_products` | Search supermarket and drugstore products |
| `compare_prices` | Compare the cheapest matching product per store |
| `optimize_shopping_list` | Split a list across the cheapest stores |
| `list_supermarkets` | List stores and product counts |
| `list_drugstores` | List drugstores and active promotion counts |
| `list_promotions` | Search current promotions by store/category |
| `search_recipes` | Search recipes by text, category, diet, or duration |
| `plan_meals` | Generate a meal plan and priced shopping list |
| `get_price_history` | Show recent price ranges |
| `create_price_alert` | Create a price or promotion alert |
| `check_price_alerts` | Check active alerts against current data |
| `save_shopping_list` | Save a shopping list |
| `load_shopping_list` | Re-price a saved list |
| `list_shopping_lists` | List saved shopping lists |
| `get_purchase_advice` | Recommend buying now or waiting |
| `find_stores` | Find nearby stored locations |
| `plan_store_route` | Group cheapest products into store stops |
| `set_budget` | Set the current weekly budget |
| `check_budget` | Price a list against a budget |
| `get_saving_tips` | Find promotion savings |
Tool names, input fields, descriptions, and responses are English. Dutch terms are retained only in synchronized source values and matching keywords required by Dutch retailer data sources.
## Docker quick start
```sh
cp .env.example .env
# Replace DB_PASSWORD and HTTP_AUTH_TOKEN with random values.
docker compose up -d --build
```
The stack contains:
- `db`: PostgreSQL 16 with `docker/init.sql`
- `mcp-server`: authenticated Streamable HTTP at `http://localhost:8000/mcp`
- `scheduler`: initial sync followed by 12-hour product/promotion/recipe syncs
The MCP and scheduler initialize the PostgreSQL schema themselves from the schema bundled in the image. A deployment consuming the published image does not need to clone this repository or mount `docker/init.sql`.
## GitHub Container Registry deployment
Every push to `main` publishes two image tags through `.github/workflows/publish-container.yml`:
```text
ghcr.io/thijserven/dutch-supermarkets-mcp:latest
ghcr.io/thijserven/dutch-supermarkets-mcp:<full-commit-sha>
```
```yaml
services:
dutch-supermarkets-db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: dutch_supermarkets
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${DUTCH_SUPERMARKETS_DB_PASSWORD}
volumes:
- dutch-supermarkets-data:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres -d dutch_supermarkets']
interval: 5s
timeout: 5s
retries: 10
dutch-supermarkets-mcp:
image: ghcr.io/thijserven/dutch-supermarkets-mcp:<full-commit-sha>
restart: unless-stopped
depends_on:
dutch-supermarkets-db:
condition: service_healthy
environment: &dutch-supermarkets-env
DB_HOST: dutch-supermarkets-db
DB_PORT: 5432
DB_NAME: dutch_supermarkets
DB_USER: postgres
DB_PASSWORD: ${DUTCH_SUPERMARKETS_DB_PASSWORD}
ENABLE_HTTP_SERVER: 'true'
HTTP_HOST: '0.0.0.0'
HTTP_PORT: 8000
HTTP_AUTH_TOKEN: ${DUTCH_SUPERMARKETS_MCP_AUTH_TOKEN}
dutch-supermarkets-scheduler:
image: ghcr.io/thijserven/dutch-supermarkets-mcp:<full-commit-sha>
restart: unless-stopped
depends_on:
dutch-supermarkets-mcp:
condition: service_healthy
environment:
<<: *dutch-supermarkets-env
SYNC_INTERVAL_MS: 43200000
command: ['bin/scheduler.js']
healthcheck:
disable: true
volumes:
dutch-supermarkets-data:
```
Check health:
```sh
curl http://localhost:8000/health
```
Connect an MCP client using either header:
```text
Authorization: Bearer <HTTP_AUTH_TOKEN>
x-mcp-token: <HTTP_AUTH_TOKEN>
```
Example Hermes MCP configuration:
```yaml
mcp_servers:
dutch_supermarkets:
url: http://mcp-server:8000/mcp
headers:
Authorization: Bearer ${HTTP_AUTH_TOKEN}
```
## Local stdio setup
Requirements: Node.js 20+ and a reachable PostgreSQL database initialized with `docker/init.sql`.
```sh
npm ci
npm run build
DB_HOST=127.0.0.1 DB_PORT=5432 DB_PASSWORD=... node bin/mcp-server.js
```
`ENABLE_HTTP_SERVER` defaults to `false`, so the CLI uses stdio. An MCP client configuration can invoke it directly:
```json
{
"mcpServers": {
"dutch-supermarkets": {
"command": "node",
"args": ["/absolute/path/to/dutch-supermarkets-mcp/bin/mcp-server.js"],
"env": {
"DB_HOST": "127.0.0.1",
"DB_PORT": "5432",
"DB_NAME": "dutch_supermarkets",
"DB_USER": "postgres",
"DB_PASSWORD": "..."
}
}
}
}
```
## Configuration
| Variable | Default | Description |
| ----------------------- | -------------------: | ---------------------------------------- |
| `DB_HOST` | `127.0.0.1` | PostgreSQL host |
| `DB_PORT` | `5432` | PostgreSQL port |
| `DB_NAME` | `dutch_supermarkets` | Database name |
| `DB_USER` | `postgres` | Database user |
| `DB_PASSWORD` | empty | Database password |
| `ENABLE_HTTP_SERVER` | `false` | Use Streamable HTTP instead of stdio |
| `HTTP_HOST` | `0.0.0.0` | HTTP bind host |
| `HTTP_PORT` | `8000` | HTTP bind port |
| `HTTP_AUTH_TOKEN` | unset | Optional HTTP bearer/custom-header token |
| `HTTP_AUTH_HEADER_NAME` | `x-mcp-token` | Custom token header |
For exposed or shared HTTP deployments, always set `HTTP_AUTH_TOKEN` and place the server behind TLS. The Docker Compose stack requires the token.
## Data synchronization
```sh
npm run sync -- prices
npm run sync -- promotions
npm run sync -- recipes
npm run sync -- all
```
Sources:
- Product prices: `checkjebon.nl/data/supermarkets.json`
- Promotions: public Folderz category pages
- Recipes: bundled Dutch recipes plus TheMealDB
These are third-party sources and can change or rate-limit requests. The sync commands fail visibly on source/database errors; existing database data remains available to the MCP server.
## Development
```sh
npm test
npm run lint
npm run typecheck
npm run build
```
The test suite covers tool parity, Zod validation, parameterized SQL behavior, transport authentication, MCP protocol calls, geographic calculations, and promotion parsing.
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing