mcp-veggie
by lovettbarron
README.md
# mcp-veggie
MCP server for tracking weekly Aarstiderne veggie box deliveries. Translates Danish produce names, provides USDA-sourced freshness windows, generates zero-waste recipes via local LLM, and alerts when items are about to expire.
Built for a family of 3 in Denmark (two adults, one texture-sensitive 7-year-old). Deployed on a K3s cluster alongside an Ollama instance.
## Tools
| Tool | Description |
|------|-------------|
| `get_current_box` | Fetch this week's box contents with translations, freshness data, and eating order |
| `generate_recipes` | Zero-waste recipes using current box items, with kid-friendly strategies |
| `get_meal_plan` | 7-day structured plan scheduling perishable items first |
| `check_alerts` | Items nearing expiration with specific waste-rescue advice |
| `analyze_waste_risk` | Items at risk of going to waste with preservation suggestions |
| `mark_item_used` | Mark an item as consumed |
| `get_eating_order` | Priority list by perishability (with knowledge-base tiebreaker) |
| `get_freshness_status` | Full freshness report with storage tips and ethylene warnings |
| `override_freshness` | Correct a freshness estimate from experience |
| `set_box_url` | Configure the Aarstiderne box URL |
## Produce Knowledge Base
A 151-item knowledge base (`src/seed/produce-knowledge.json`) provides Denmark-specific produce intelligence loaded into memory at startup. Each entry includes:
- **Danish season data** — peak months, source (Danish farm vs import)
- **Yield notes** — practical quantities for meal planning ("500g carrots = 400ml soup base for 2")
- **Preservation methods** — 2-4 practical methods per item with effort level and shelf life
- **Waste rescue** — specific "it's going soft, do THIS now" advice per item
- **Flavor pairings** — what goes well together and what to avoid
- **Kid strategy** — acceptance level, texture notes, winning preparations, and hiding methods for a texture-sensitive child
- **Ethylene data** — producer/sensitive classification drives storage co-location warnings
- **Box priority** — `days_to_use_first_in_box` (1-3) used as eating-order tiebreaker
This data enriches LLM prompts for recipes and meal plans, powers waste-rescue suggestions in alerts, and provides ethylene storage warnings in freshness reports.
## Setup
```bash
cp .env.example .env
# Edit .env with your Ollama host and box URL
npm install
npm run build
npm start
```
Requires:
- Node.js 22+
- Ollama running with `qwen3.6:27b` (or any model via `LLM_MODEL` env var)
- An Aarstiderne box subscription URL
## Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | 3006 | HTTP server port |
| `DB_PATH` | ./data/veggie.db | SQLite database path |
| `LLM_BASE_URL` | http://localhost:11434 | Ollama API base URL |
| `LLM_MODEL` | qwen3.6:27b | Model for translations/recipes |
| `LLM_TIMEOUT` | 120000 | LLM request timeout (ms) |
## Architecture
- **Transport:** Streamable HTTP (MCP SDK 1.29.0) -- stateless per-request
- **Database:** SQLite with WAL mode, Drizzle ORM
- **LLM:** Ollama native API with `think: false` for fast structured output
- **Provider:** Aarstiderne BOM API (no auth required)
- **Translation:** Seed cache of 93 Danish produce names + LLM fallback
- **Freshness:** 151-item USDA dataset + LLM fallback with conservative bias
- **Produce Knowledge:** 151-item in-memory knowledge base with Danish-specific context, kid strategies, ethylene data, and preservation methods
## K8s Deployment
```bash
kubectl apply -f k8s/
```
The deployment expects:
- A PVC named `mcp-veggie-data` for the SQLite file
- Ollama accessible at the `LLM_BASE_URL` in the configmap
- `ghcr-creds` imagePullSecret for the container image
## Connecting via Hermes
Register the MCP server endpoint in your Hermes gateway configuration:
```yaml
servers:
- name: mcp-veggie
url: http://mcp-veggie.mcp-veggie.svc.cluster.local:3006/mcp
transport: streamable-http
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues