nutrition-mcp/README.md
Anthony Merlo 5beef81d70 docs: README.md, AGENTS.md, CLAUDE.md
- README: human-facing with tech stack, 14 nutrient table, 13 tools,
  env vars, build/run/deploy instructions, Hermes integration
- AGENTS/CLAUDE: build commands, architecture, module map, SQLite
  schema, conventions, tracked nutrients, session protocol

Closes nutrition-mcp-yd5, nutrition-mcp-4lv
2026-08-20 16:53:33 +01:00

165 lines
No EOL
5.5 KiB
Markdown

# Nutrition MCP
Personal calorie and nutrient tracking MCP server. Looks up food via OpenFood Facts, logs meals with portion-scaled nutrients, and tracks daily intake against gout and hypertension-aware goals.
## Tech Stack
- [Rust](https://www.rust-lang.org/) — Systems language
- [rmcp](https://github.com/modelcontextprotocol/rust-sdk) — Official Rust MCP SDK (streamable HTTP transport)
- [axum](https://github.com/tokio-rs/axum) 0.8 — Web framework for HTTP transport + auth middleware
- [sqlx](https://github.com/launchbadge/sqlx) 0.8 — Async SQLite
- [reqwest](https://github.com/seanmonstar/reqwest) 0.12 — HTTP client for OpenFood Facts APIs
- [SQLite](https://www.sqlite.org/) with FTS5 — Local database + full-text search
## Health Context
This tracker is configured for two specific health conditions:
- **Gout** — Tracks fructose (15g/day limit) and alcohol (0 limit). Both are known gout triggers.
- **Hypertension** — Tracks salt (6g/day, NHS guideline), potassium (3500mg, helps lower BP), calcium (700mg), magnesium (300mg), and cholesterol (300mg).
## 14 Tracked Nutrients
| Nutrient | OFF field | Default goal | Unit | Reason |
|----------|-----------|-------------|------|--------|
| Energy | `energy-kcal_100g` | 2500 | kcal | General |
| Protein | `proteins_100g` | 150 | g | General |
| Carbohydrates | `carbohydrates_100g` | 300 | g | General |
| Fat | `fat_100g` | 70 | g | General |
| Fiber | `fiber_100g` | 30 | g | General |
| Sugars | `sugars_100g` | 90 | g | General |
| Saturated fat | `saturated-fat_100g` | 20 | g | Hypertension |
| Salt | `salt_100g` | 6 | g | Hypertension (key) |
| Fructose | `fructose_100g` | 15 | g | Gout (key) |
| Alcohol | `alcohol_100g` | 0 | % vol | Gout (key) |
| Potassium | `potassium_100g` | 3500 | mg | Hypertension (key) |
| Calcium | `calcium_100g` | 700 | mg | Hypertension |
| Magnesium | `magnesium_100g` | 300 | mg | Hypertension |
| Cholesterol | `cholesterol_100g` | 300 | mg | Hypertension |
## MCP Tools (13)
### Food Lookup
- `search_food(query, page_size?)` — Full-text search via OpenFood Facts Search-a-licious
- `get_food_by_barcode(barcode)` — Product lookup by barcode via OFF API v3
### Logging
- `log_food(product_code, grams?, servings?, date?, meal?)` — Log OFF product with portion scaling
- `log_custom_food(name, calories, nutriments?, grams, date?, meal?)` — Log homemade/restaurant food
- `delete_entry(id)` — Remove a logged entry
### Summary & History
- `daily_summary(date?)` — All 14 nutrients vs goals, remaining, entry list
- `history(days?)` — Last N days of totals (default 7)
- `list_entries(date?)` — List entries with IDs for deletion
### Goals
- `get_goals()` — Current daily nutrient targets
- `set_goals(goals)` — Update goals (partial merge)
### Weight
- `log_weight(weight_kg, date?)` — Log body weight in kg
- `weight_history(days?)` — Weight trend (default 30 days)
### Future
- `bulk_import(parquet_url?)` — Stub for offline Parquet import
## Build
```bash
cargo build --release
```
Binary: `target/release/nutrition-mcp`
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `NUTRITION_MCP_BIND` | `0.0.0.0:9432` | Bind address |
| `NUTRITION_MCP_API_KEY` | (random UUID) | Bearer token for auth |
| `NUTRITION_MCP_DB_PATH` | `~/.local/share/nutrition/nutrition.db` | SQLite database path |
| `NUTRITION_MCP_OFF_USER_AGENT` | `NutritionMCP/0.1.0 (personal use)` | User-Agent for OFF API |
## Run
```bash
NUTRITION_MCP_API_KEY=your-secret-key \
NUTRITION_MCP_BIND=0.0.0.0:9432 \
./target/release/nutrition-mcp
```
### Health Check
```bash
curl http://localhost:9432/health
# → OK
```
### MCP Connect
```bash
curl -X POST http://localhost:9432/mcp \
-H "Authorization: Bearer your-secret-key" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}},"id":1}'
```
## Deploy as systemd Service
```bash
# Create service file
cat > ~/.config/systemd/user/nutrition-mcp.service << 'EOF'
[Unit]
Description=Nutrition MCP Server
After=network.target
[Service]
ExecStart=%h/workspace/nutrition-mcp/target/release/nutrition-mcp
Environment=NUTRITION_MCP_BIND=0.0.0.0:9432
Environment=NUTRITION_MCP_API_KEY=your-secret-key
Environment=NUTRITION_MCP_DB_PATH=%h/.local/share/nutrition/nutrition.db
Environment=NUTRITION_MCP_OFF_USER_AGENT=NutritionMCP/0.1.0 (personal use; contact: atradeus@pm.me)
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
EOF
# Enable linger (survive logout)
loginctl enable-linger $USER
# Start
systemctl --user daemon-reload
systemctl --user enable --now nutrition-mcp
```
## Connect from Hermes
```bash
hermes mcp add nutrition --url http://localhost:9432 --header "Authorization: Bearer your-secret-key"
```
## Connect from Laptop (LAN)
```bash
hermes mcp add nutrition --url http://chronos:9432 --header "Authorization: Bearer your-secret-key"
```
## Data Sources
- [OpenFood Facts Search-a-licious](https://search.openfoodfacts.org) — Full-text product search
- [OpenFood Facts API v3](https://world.openfoodfacts.org/api/v3) — Barcode lookups
- [OpenFood Facts Parquet](https://huggingface.co/datasets/openfoodfacts/product-database) — Future offline bulk import (7.82 GB, 4.7M products)
All food data is cached locally in SQLite with FTS5 for instant repeat lookups.
## Architecture
See [AGENTS.md](./AGENTS.md) for full project instructions, conventions, and module map.
## License
MIT