nutrition-mcp/AGENTS.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

4.1 KiB
Raw Blame History

Agent Instructions

This project uses bd (beads) for issue tracking. Run bd prime for full workflow context.

Build & Test

cargo build --release          # Build binary
cargo test                     # Run unit tests
./target/release/nutrition-mcp # Run server (needs env vars)

Smoke Test

# Start server
NUTRITION_MCP_BIND=127.0.0.1:9432 NUTRITION_MCP_API_KEY=test \
  NUTRITION_MCP_DB_PATH=/tmp/test.db ./target/release/nutrition-mcp &

# Health check
curl http://127.0.0.1:9432/health

# MCP initialize
curl -X POST http://127.0.0.1:9432/mcp \
  -H "Authorization: Bearer test" \
  -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}'

Architecture Overview

MCP server exposing 13 tools for personal nutrition tracking. Streamable HTTP transport with Bearer token auth.

Module Map

src/
├── main.rs     — Entry point: axum server, auth middleware, /health endpoint
├── config.rs   — Config struct from env vars (bind, api_key, db_path, user_agent)
├── db.rs       — SQLite schema, migrations, DbPool type, TRACKED_NUTRIENTS const, DEFAULT_GOALS_JSON
├── api.rs      — OffClient: Search-a-licious + v3 barcode + SQLite cache (FTS5)
└── tools.rs    — NutritionServer: 13 MCP tools via #[tool_router] + ServerHandler impl

SQLite Schema

  • products — OFF cache: code (PK), product_name, brands, nutriments (JSON), serving_quantity, serving_size, image_url
  • products_fts — FTS5 virtual table on product_name (synced via triggers)
  • entries — Food log: id, date, meal, product_code, food_name, grams, servings, nutriments (JSON, scaled to portion)
  • daily_goal — Single row (id=1), goals JSON with 14 nutrient targets
  • weight_log — id, date, weight_kg

Nutrient Storage

All nutrients stored as JSON blob in nutriments TEXT column (verbatim from OFF API). Daily summaries use json_extract() or Rust-side parsing to aggregate the 14 tracked nutrients.

Portion Scaling

Nutrients are stored per-100g in OFF data. When logging, scale_nutriments() multiplies each value by grams / 100.0. For servings, grams = servings * serving_quantity.

Meal Auto-Detection

  • breakfast: before 11:00
  • lunch: 11:00–15:00
  • dinner: 15:00–21:00
  • snack: after 21:00

Conventions & Patterns

  • JSON nutriments — Never hardcode nutrient columns. Store OFF nutriments verbatim as JSON, query at runtime.
  • "no data" vs 0 — Micronutrients (potassium, calcium, magnesium) are sparse in OFF. Summary shows "no data" when no entries have the nutrient, not 0.
  • Env vars only — No config files. All settings via environment variables.
  • API-first — Always check SQLite cache first, fall back to OFF API, cache results.
  • User-Agent — Always send custom User-Agent to OFF API (good citizenship).

Tracked Nutrients (14)

energy_kcal    → energy-kcal_100g
protein        → proteins_100g
carbohydrates  → carbohydrates_100g
fat            → fat_100g
fiber          → fiber_100g
sugars         → sugars_100g
saturated_fat  → saturated-fat_100g
salt           → salt_100g
fructose       → fructose_100g      (gout)
alcohol        → alcohol_100g        (gout)
potassium      → potassium_100g      (hypertension)
calcium        → calcium_100g        (hypertension)
magnesium      → magnesium_100g      (hypertension)
cholesterol    → cholesterol_100g    (hypertension)

Non-Interactive Shell Commands

ALWAYS use non-interactive flags to avoid hanging on confirmation prompts.

cp -f source dest           # NOT: cp source dest
rm -f file                  # NOT: rm file

Session Completion

  1. File issues for remaining work - bd create for follow-up items
  2. Run quality gates - cargo build --release && cargo test
  3. Close completed issues - bd close <id1> <id2> ...
  4. PUSH - git add -A && git commit -m "..." && git push
  5. Verify - git status must show clean working tree