Skip to main content
Glama
lovettbarron

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