- 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
165 lines
No EOL
5.5 KiB
Markdown
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 |