nutrition_db
by harmehak0173
README.md
# 🥗 MCP Nutrition - AI Meal Planner
Generate a **personalized 7-day meal plan** from your profile and goal, get **daily
calorie catch-up** when you fall short, and **track your progress** over time. It runs as a
**FastAPI web app** and, because the same engine is exposed over the **Model Context Protocol
(MCP)**, also as **AI tools, resources, and prompts any MCP client (Claude Desktop, etc.) can use**.
The intelligence is a deliberate blend:
- 🤖 **OpenAI** proposes concrete, varied meals for each day.
- 🥦 **API Ninjas** looks up macros for each food when your key returns them. **Heads-up:** the free API Ninjas tier gates `calories`/`protein`, so in practice many values fall back to the bundled ~29-food catalog or an Atwater estimate (see [Data & limits](#data--limits)).
- 🌤️ **OpenWeather** nudges calories/hydration for the day's conditions.
- 🧮 **Deterministic Python** computes the targets, keeps the LLM out of the arithmetic, reconciles each day to the **calorie** goal, and runs the catch-up math - the parts that are guaranteed and unit-tested.
> Runs offline too: with **no API keys**, it falls back to a bundled food catalog + cache, so
> `git clone && run` works immediately.
---
## Quickstart
```bash
# 1. Install (uv recommended)
uv sync --extra dev
# 2. (optional) add API keys for live LLM meals + real macros
cp .env.example .env # then edit .env
# 3. Run the web app
uv run uvicorn app.main:app --reload
# open http://127.0.0.1:8000
```
Prefer pip? `python -m venv .venv && . .venv/Scripts/activate && pip install -e ".[dev]"`.
### Environment (all optional)
| Key | Enables | Without it |
|-----|---------|-----------|
| `OPENAI_API_KEY` | LLM-generated meals | meals come from the bundled catalog |
| `API_NINJAS_KEY` | real macro numbers | macros come from cache / catalog |
| `OPENWEATHER_API_KEY` | weather-based adjustment | adjustment is skipped |
---
## Run it as an MCP server
The planner is also a stdio MCP server named `nutrition_db`:
```bash
uv run nutrition-mcp # or: python -m mcp_server
```
Register it in an MCP client (e.g. Claude Desktop `claude_desktop_config.json`):
```json
{
"mcpServers": {
"nutrition_db": {
"command": "uv",
"args": ["run", "nutrition-mcp"],
"cwd": "/absolute/path/to/MCP Nutrition"
}
}
}
```
It exposes all three MCP primitives, not just tools:
- **Tools:** `get_food_nutrients`, `get_current_conditions`, `compute_targets`, `generate_weekly_meal_plan`, `log_daily_intake`, `adjust_daily_calories`.
- **Resources** (read-only context): `nutrition://catalog`, `nutrition://profile`, `nutrition://targets`, `nutrition://log/today`, `nutrition://history`.
- **Prompts** (guided flows): `plan_my_week`, `log_my_meal`, `what_should_i_eat_now`.
---
## How it works
```mermaid
flowchart LR
UI["Web UI (form)"] -->|HTTP| API["FastAPI · app/"]
MCP["MCP client<br/>(Claude Desktop)"] -->|tools · resources · prompts| SRV["nutrition_db · mcp_server/"]
API --> CORE
SRV --> CORE
subgraph CORE["core/ engine - single source of truth"]
direction LR
T["targets<br/>(BMR→TDEE→goal)"] --> P["planner"]
P --> R["reconcile ±10%"]
ADJ["catch-up adjuster"]
H["history"]
end
P -->|propose foods| OA["OpenAI"]
P -->|ground macros| AN["API Ninjas"]
T -->|weather adjust| OW["OpenWeather"]
```
`core/` is the single source of truth; the web app and the MCP server are thin layers over it.
See [`docs/DECISIONS.md`](docs/DECISIONS.md) for the design tradeoffs and roadmap.
**Plan generation** (`core/planner.py`), per day: OpenAI proposes foods → API Ninjas returns real
macros (cached) → deterministic code scales portions to hit the calorie target (±10%). A rolling
"avoid recently-used items" list keeps the week varied. No OpenAI key? The bundled catalog builds
the day instead.
**Calorie catch-up** (`core/adjuster.py`): compares logged intake to target. If you're under, it
suggests catch-up foods for the meals you have left today, or rolls a **capped** portion of the
shortfall into tomorrow. (This is the opposite of naively lowering the goal when you under-eat.)
**Targets** (`core/targets.py`): Mifflin-St Jeor BMR → activity TDEE → goal adjustment
(-500 weight loss / +300 muscle gain) → macro split.
---
## Project layout
```
core/ deterministic engine + service facade + API/LLM clients (the brains)
mcp_server/ nutrition_db MCP server (tools + resources + prompts over core/)
app/ FastAPI backend + minimal web UI (form, plan, catch-up, progress chart)
data/ food_catalog.json (fallback), nutrition_cache.json, state.json (runtime)
evals/ plan-quality eval harness + SCORECARD.md (python -m evals)
docs/ DECISIONS.md (design tradeoffs & roadmap)
tests/ pytest suite (targets, planner, adjuster, allergens, service, evals)
```
## Testing & evals
```bash
uv run pytest -q # 34 tests
uv run ruff check .
uv run python -m evals # regenerate evals/SCORECARD.md
```
Tests run the real engine in offline mode (deterministic via the catalog) and use small fakes to
exercise the LLM path without a network call.
**Plan-quality evals** ([`evals/`](evals/), scorecard: [`evals/SCORECARD.md`](evals/SCORECARD.md))
score generated plans across a golden set of profiles (goals × diets × allergies) on calorie
adherence, **100% allergen safety**, protein adequacy, diet compliance, and variety. CI gates the
non-negotiables - measuring a non-deterministic LLM system, not just unit-testing pure functions.
---
## Data & limits
Be clear-eyed about what this does and doesn't guarantee:
- **Macro source.** Authoritative macros come from API Ninjas *only when your key returns them*. On the free tier `calories`/`protein` are premium-gated, so values fall back to the curated **~29-food catalog** (`data/food_catalog.json`) or an Atwater (4/4/9) estimate. The bundled catalog is what makes offline mode work.
- **"On target" means calories.** Days are reconciled to the **calorie** target (±10%); protein/carb/fat are shown as guidance and a day is flagged when protein runs low, but macros aren't enforced.
- **Allergens.** Typed allergies are expanded to ingredient keywords (`core/allergens.py`) and excluded from catalog, LLM-proposed, and catch-up foods - but it's **best-effort keyword matching, not a medical guarantee.** Verify ingredients yourself.
- **Not medical advice.** Estimates only; not for pregnancy, medical conditions, or disordered eating. Single-user, local state; no accounts or sync.
## Provenance
This started as an MCP nutrition benchmark server and grew into a standalone product. All code here
is original work by **harmehak0173**; it has no dependency on the original benchmark framework.
## License
MIT © 2026 harmehak0173 - see [LICENSE](LICENSE).
TDQS
A3.6/5.0
Scored across 6 tools
Disambiguation5/5
Each tool has a clearly distinct purpose, from computing targets to logging intake and generating meal plans. The weather tool is unrelated but still unique.
Naming Consistency5/5
All tool names follow a consistent verb_noun pattern in snake_case, making them predictable and easy to understand.
Tool Count5/5
With 6 tools, the server is well-scoped for nutrition tracking without being overwhelming or underwhelming.
Completeness4/5
Core workflows are covered (targets, food lookup, logging, planning), but missing update/delete for logs and the weather tool is extraneous.
Maintenance
ActivityInactive
ResponsivenessNo issues