Calorie Tracker MCP
# Calorie Tracker MCP
A local, JSON-first calorie and protein tracker for agents and shell workflows. It ships a
`calorie-tracker` CLI and a protocol-safe `calorie-tracker-mcp` stdio server. Every profile is
stored in its own SQLite database; no service, database server, open port, or account is needed.
## Prerequisites
- Fedora Linux (the release smoke target is Fedora 44).
- Python 3.12 or newer with `venv` and `pip` available.
- A project-built `calorie_tracker_mcp-*.whl` file.
The runtime uses the official MCP Python SDK and Pydantic. Installation may need access to the
configured Python package index to resolve those declared wheel dependencies. The application
itself performs no nutrition lookups, telemetry, or other network calls.
## Install
Build a wheel from a trusted checkout, then give that exact artifact to the installer:
```bash
python3 -m build
./scripts/install-fedora.sh "$PWD/dist/calorie_tracker_mcp-0.2.0-py3-none-any.whl"
```
The script requires no elevated privileges and does not edit shell configuration. It creates an
isolated venv at
`${XDG_DATA_HOME:-$HOME/.local/share}/calorie-tracker/venv` and prints the absolute paths of both
executables. For convenience in the examples below:
```bash
CLI="$HOME/.local/share/calorie-tracker/venv/bin/calorie-tracker"
```
## Separate agent profiles
Each agent profile must receive a unique `CALORIE_TRACKER_DB` absolute path. Do not point two
identities at the same profile database merely because the executable is shared:
```bash
export CALORIE_TRACKER_DB="$HOME/.local/share/calorie-tracker/profiles/alex/calories.db"
export CALORIE_TRACKER_TIMEZONE=America/New_York
"$CLI" doctor
```
The environment timezone initializes a new profile. After initialization, the timezone stored in
that database is authoritative. Inspect or deliberately change it with `profile show` and
`profile set-timezone`.
## V2 nutrients and database compatibility
V2 profile databases are intentionally incompatible with V1. Back up and retain the V1
database, then configure CALORIE_TRACKER_DB to a new path before starting V2. V2 never
migrates, resets, or overwrites a V1 database.
Meals support optional carbohydrate, fat, fiber, sugar, and sodium estimates.
All five estimates are optional, and missing summary values count as zero.
Gram values use one decimal place for carbohydrate, fat, fiber, and sugar.
Sodium uses whole milligrams. Meal items remain calorie/protein-only—the expanded nutrient
estimates apply to authoritative meal totals.
## MCP configuration
Copy and adapt [`docs/examples/mcp-config.json`](docs/examples/mcp-config.json). Its command and
database values are absolute paths. Keep the same installed `calorie-tracker-mcp` command for
multiple profiles, but assign every server a distinct database:
```json
{
"command": "/home/alex/.local/share/calorie-tracker/venv/bin/calorie-tracker-mcp",
"env": {
"CALORIE_TRACKER_DB": "/home/alex/.local/share/calorie-tracker/profiles/alex/calories.db",
"CALORIE_TRACKER_TIMEZONE": "America/New_York"
}
}
```
The MCP server uses stdio only. Its standard output is reserved for JSON-RPC protocol frames;
sanitized diagnostics use standard error.
## CLI examples
Commands emit one stable JSON envelope by default. Add `--pretty` for indented JSON; selected read
commands also accept `--output table`.
```bash
"$CLI" doctor --pretty
"$CLI" meal add --input-json '{
"idempotency_key":"agent-run-20260717-lunch-1",
"local_date":"2026-07-17",
"meal_type":"lunch",
"estimated_total_calories":500,
"estimated_total_protein_g":35,
"estimated_total_carbohydrate_g":42.3,
"estimated_total_fat_g":14.7,
"estimated_total_fiber_g":5.1,
"estimated_total_sugar_g":3.8,
"estimated_total_sodium_mg":620,
"confidence":"medium",
"raw_text":"Chicken and rice"
}'
"$CLI" meal list --from 2026-07-01 --to 2026-07-31 --output table
"$CLI" meal get MEAL_ID
```
Complex JSON may instead come from a file with `--input meal.json` or standard input with
`--input -`. The external agent supplies all calorie and protein estimates; meal totals remain
authoritative even when item estimates are included.
Each item requires a nonblank free-form `quantity` such as `1 bowl`, `2 large`, or
`about 200 g`. Missing or blank quantities are rejected as `validation_error` before storage.
## Past dates
Meals may be recorded for current or past dates. Supply `local_date`; `local_time` is optional so
historical entries do not invent precision. Dates are bucketed in the profile timezone. Impossible
DST local times are rejected, while ambiguous times are retained with a warning.
Future meal dates are rejected using the current date in that profile's timezone. Retrying an
already-created idempotent request still returns its original meal after timezone changes.
## Idempotency
Every meal creation requires a caller-generated `idempotency_key`. Retrying the same key with the
same canonical payload returns the existing meal. Reusing it for different data returns an
`idempotency_conflict`. Use a stable operation identifier, not a reusable label such as `lunch`.
## Revisions
Updates, soft deletion, and restoration use optimistic revisions. Read the current `revision`, then
provide it explicitly:
```bash
"$CLI" meal update MEAL_ID --expected-revision 1 --input-json '{"notes":"Updated"}'
"$CLI" meal delete MEAL_ID --expected-revision 2
"$CLI" meal restore MEAL_ID --expected-revision 3
"$CLI" meal history MEAL_ID --include-snapshots
```
A stale value returns `revision_conflict`. Deletes are recoverable and each mutation stores an
immutable history snapshot.
Successful updates return the updated `meal`, an item-total `audit`, and warnings for ambiguous DST
times or material differences between authoritative meal totals and item subtotals.
## Goals
Goals are effective-dated, so changing a target does not rewrite historical meaning:
```bash
"$CLI" goals set --effective-from-date 2026-07-01 \
--daily-calorie-target 2200 --daily-protein-g-target 150
"$CLI" goals get --date 2026-07-17
"$CLI" goals history --output table
```
## Summaries
Request one day or an inclusive range. Summaries exclude deleted meals and report totals, averages,
goal progress, remaining values, meal-type breakdowns, confidence counts, and per-day details.
```bash
"$CLI" summary --date 2026-07-17 --output table
"$CLI" summary --from 2026-07-01 --to 2026-07-31
```
## Export and backup
Exports are bounded meal-data extracts; backups are complete SQLite copies. Existing output files
are refused unless `--overwrite` is explicit.
```bash
"$CLI" export --format json --from 2026-07-01 --to 2026-07-31 \
--output-path "$HOME/private/calories-july.json"
"$CLI" export --format csv --output-path "$HOME/private/calories.csv"
"$CLI" db backup "$HOME/private/calories-backup.db"
"$CLI" db info --output table
```
Protect exports and backups like the source database. Verify a backup before relying on it.
## Upgrade from V1 to V2
V2 uses a new, incompatible database. Do not install V2 until the V1 database is backed up and
the exact V1 wheel is retained for rollback. The upgrade replaces both executables in the shared
managed venv, but it never changes the V1 database.
### 1. Back up V1 and retain rollback assets
Set absolute paths for the current profile, its backup, both wheels, and the managed CLI. Place
the exact trusted `0.1.0` wheel used by the current installation at `V1_WHEEL` before continuing:
```bash
CLI="$HOME/.local/share/calorie-tracker/venv/bin/calorie-tracker"
V1_DB="$HOME/.local/share/calorie-tracker/profiles/alex/calories.db"
V1_BACKUP="$HOME/private/calories-v1-backup.db"
V1_WHEEL="$HOME/private/calorie_tracker_mcp-0.1.0-py3-none-any.whl"
V2_WHEEL="$PWD/dist/calorie_tracker_mcp-0.2.0-py3-none-any.whl"
test -f "$V1_WHEEL"
CALORIE_TRACKER_DB="$V1_DB" "$CLI" doctor --pretty
CALORIE_TRACKER_DB="$V1_DB" "$CLI" db backup "$V1_BACKUP"
```
Keep both `V1_DB` and `V1_BACKUP`. Do not rename, replace, or delete the V1 database.
### 2. Build and install V2
From a trusted V2 checkout, build the wheel and pass that exact artifact to the installer:
```bash
python3 -m build
test -f "$V2_WHEEL"
./scripts/install-fedora.sh "$V2_WHEEL"
```
The installer upgrades the existing managed venv in place. Its `calorie-tracker` CLI and
`calorie-tracker-mcp` server now both run version `0.2.0`; their absolute paths stay the same.
### 3. Initialize the new V2 database for the CLI
Choose a new absolute path. Never set `V2_DB` to `V1_DB`:
```bash
V2_DB="$HOME/.local/share/calorie-tracker/profiles/alex-v2/calories.db"
export CALORIE_TRACKER_DB="$V2_DB"
export CALORIE_TRACKER_TIMEZONE=America/New_York
"$CLI" doctor --pretty
"$CLI" profile show --pretty
"$CLI" meal list --pretty
```
`doctor` creates the V2 database and reports schema version `2`. A new V2 profile starts with no
meals or goals.
### 4. Update the MCP configuration
Point the MCP server at the same new V2 database. For example:
```json
{
"command": "/home/alex/.local/share/calorie-tracker/venv/bin/calorie-tracker-mcp",
"env": {
"CALORIE_TRACKER_DB": "/home/alex/.local/share/calorie-tracker/profiles/alex-v2/calories.db",
"CALORIE_TRACKER_TIMEZONE": "America/New_York"
}
}
```
Save the configuration, restart the MCP client, and verify that its calorie-tracker server
starts cleanly and exposes the expected tools, including `log_meal`, `list_meals`, and
`get_summary`.
### 5. Understand the data boundary
V2 does not import or migrate V1 meal data. The new V2 database starts empty, while the original
V1 database remains unchanged at `V1_DB`. Keep the two database paths separate; do not share a
database between V1 and V2 processes.
### 6. Roll back to V1
Stop the MCP client before rollback. Reinstall the retained V1 wheel, restore the original CLI
database environment, and change the MCP configuration back to the original V1 database path:
```bash
./scripts/install-fedora.sh "$V1_WHEEL"
export CALORIE_TRACKER_DB="$V1_DB"
CALORIE_TRACKER_DB="$V1_DB" "$CLI" doctor --pretty
```
Then restore the MCP configuration's `CALORIE_TRACKER_DB` value to the absolute V1 path and
restart the MCP client. Never open the V1 database with the V2 executable. Data written to the
separate V2 database is not merged back into V1.
## Removal
The safe default removes only the managed venv and preserves all profile databases:
```bash
./scripts/uninstall-fedora.sh
```
Permanent removal is a separate, explicit operation. The script prints the exact data directory
before deleting it:
```bash
./scripts/uninstall-fedora.sh --delete-data
```
Back up first. `--delete-data` removes the configured
`${XDG_DATA_HOME:-$HOME/.local/share}/calorie-tracker` path and securely erases every profile
through its pinned directory descriptor. To guarantee that a concurrent path replacement can
never cause an unrelated directory to be removed, the operation intentionally retains one empty,
private `0700` directory named `.calorie-tracker-deleted-*` under the same XDG data root. Future
installs and removals ignore these data-free tombstones.
## Privacy
Data remains local unless you deliberately export, back it up, or expose it through another tool.
The profile directory is created with mode `0700`; database, backup, and export files are protected
with mode `0600`. SQL is parameterized, operational logs omit meal contents, and MCP cannot change
its configured database path. There is no telemetry or application-initiated network access.
## Troubleshooting
- **`Python 3.12 or newer is required`**: install a supported Fedora Python and retry.
- **Wheel not found**: pass the path to an existing `.whl`, not a package name or source tree.
- **Dependency installation fails**: verify pip's configured index/network and retry the same wheel.
- **`configuration_error`**: check `CALORIE_TRACKER_DB`, the IANA timezone, and absolute paths.
- **`storage_error` or a failed doctor check**: verify directory ownership, free disk space, database
writability, integrity output, and that no unsupported older process is holding the profile.
- **Wrong meals appear**: two agents likely share `CALORIE_TRACKER_DB`; give each a unique database.
- **Revision conflict**: fetch the current meal, review the new revision, and retry intentionally.
- **Database busy**: allow the bounded lock wait to complete and ensure long-lived clients close.
Run `calorie-tracker --help` or command-level `--help` for the complete JSON command contract.
TDQS
Scored across 11 tools
Each tool targets a distinct operation on meals, goals, or summaries. get_meal/get_meal_history/list_meals are differentiated by single-item, revision-history, and filtered-list purposes. Update/delete/restore are clearly distinct state-transition actions with unique semantics.
All tools follow a consistent verb_noun snake_case pattern (get_, set_, list_, log_, update_, delete_, restore_, export_, log_). Verbs are apt and descriptive, and the pattern is uniform throughout with no stylistic mixing.
Eleven tools is well within the ideal 3-15 range for a calorie tracker domain. Each tool earns its place: core CRUD (log/get/list/update/delete/restore), goals management, history, summary reporting, and export capabilities. No redundancy or bloat.
The surface covers the full meal lifecycle (log, read, list, update, delete, restore), goals get/set, history, summary, and export—a thorough set. Minor gaps exist, such as no bulk-delete or goal-archival/cleanup operations, but agents can accomplish all core workflows without dead ends.