Skip to main content

cronometer-api-mcp

License: MIT CI Build Docker image PyPI

Hosted version for Claude.ai, ChatGPT, and Grok coming soon. Join the waitlist →

An MCP (Model Context Protocol) server for Cronometer nutrition tracking, built on the reverse-engineered mobile REST API.

Unlike cronometer-mcp, which takes a comprehensive GWT-RPC approach against Cronometer's web backend, this server talks to the same JSON REST API used by the Cronometer Android app -- with clean payloads and stable, versioned endpoints.

Features

  • Food log -- diary entries with food names, amounts, meal groups
  • Nutrition data -- daily macro/micro totals and nutrition scores with per-nutrient confidence
  • Food search -- search the Cronometer food database, get detailed nutrition info
  • Diary management -- add/remove entries, copy days, mark days complete
  • Custom foods -- create foods with custom nutrition data
  • Macro targets -- read weekly schedule and saved templates
  • Fasting -- view history and aggregate statistics
  • Biometrics -- weight, body fat, heart rate, and other tracked metrics over a date range

Quick Start

1. Install uv

curl -LsSf https://astral.sh/uv/install.sh | sh

2. Set credentials

export CRONOMETER_USERNAME="your@email.com"
export CRONOMETER_PASSWORD="your-password"

Optional: two-factor authentication

If the account has two-factor authentication enabled, /api/v2/login answers TOTP_CODE_REQUIRED unless the request carries the current 6-digit code. Give the server the base32 key that Cronometer showed when 2FA was set up (the same key you scanned into your authenticator app) and it derives the code itself at every login (RFC 6238, SHA-1, 30 s period):

export CRONOMETER_TOTP_SECRET="ABCD EFGH IJKL MNOP QRST UVWX YZ23 4567"

Spaces and lowercase are fine. Leave it unset for accounts without 2FA.

Optional: override the account timezone

Diary entries are stamped in your Cronometer account's timezone, which the server reports at login. If that zone is wrong (for example, an older build had reset it) you can force a specific IANA zone without changing your account settings:

export CRONOMETER_ACCOUNT_TZ="America/Los_Angeles"

When set, this takes precedence over both the value reported at login and any cached session, so it also overrides a stale cached timezone.

3. Configure your MCP client

uvx downloads and runs the server on demand -- no separate install step.

OpenCode (opencode.json)

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "cronometer": {
      "type": "local",
      "command": ["uvx", "cronometer-api-mcp"],
      "environment": {
        "CRONOMETER_USERNAME": "{env:CRONOMETER_USERNAME}",
        "CRONOMETER_PASSWORD": "{env:CRONOMETER_PASSWORD}",
        "CRONOMETER_TOTP_SECRET": "{env:CRONOMETER_TOTP_SECRET}",
        "CRONOMETER_ACCOUNT_TZ": "{env:CRONOMETER_ACCOUNT_TZ}"
      },
      "enabled": true
    }
  }
}

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "cronometer": {
      "command": "uvx",
      "args": ["cronometer-api-mcp"],
      "env": {
        "CRONOMETER_USERNAME": "your@email.com",
        "CRONOMETER_PASSWORD": "your-password",
        "CRONOMETER_TOTP_SECRET": "your-base32-key",
        "CRONOMETER_ACCOUNT_TZ": "America/Los_Angeles"
      }
    }
  }
}

Available Tools

Food Log & Nutrition

Tool Description
get_food_log Diary entries for a date, each enriched with food name, source, serving measure/count, and that food's per-entry nutrient contribution, plus an energy_summary (target/consumed/remaining kcal) and a nutrition_summary of consumed totals for every tracked nutrient
get_daily_nutrition Consumed macro and micronutrient totals for every nutrient tracked in Cronometer
get_nutrition_scores Category scores (Vitamins, Minerals, etc.) with per-nutrient consumed amounts and confidence levels

Food Search & Details

Tool Description
search_foods Search the Cronometer food database by name
get_food_details Full nutrition profile and serving sizes for a food

Diary Management

Tool Description
add_food_entry Log a food serving to the diary
remove_food_entry Remove one or more diary entries
add_custom_food Create a custom food with specified nutrition and optional barcodes
update_custom_food Edit a custom food in place: name, nutrition, serving size, or barcodes
delete_custom_food Retire a custom food so it leaves search and the Custom Foods list (existing diary entries are kept)
add_recipe Create a recipe from existing foods referenced by ID and gram weight
import_recipe Create a recipe from a free-text ingredient list; Cronometer matches each line to a database food and converts the amount to grams
copy_day Copy all entries from the previous day
mark_day_complete Mark a diary day as complete or incomplete

Targets & Tracking

Tool Description
get_macro_targets Weekly macro schedule and saved target templates
get_fasting_history Fasting history within a date range
get_fasting_stats Aggregate fasting statistics
list_biometrics List trackable biometric metrics and their units
get_biometrics Biometric time series (e.g. weight, body fat) within a date range

All date parameters use YYYY-MM-DD format and default to today when omitted.

Relative dates and recent days

get_food_log, get_daily_nutrition, and get_nutrition_scores also accept "today", "yesterday", and "N days ago" as their date. These are resolved at call time using your Cronometer account timezone, so Claude can pass relative inputs without relying on dates from earlier in a long conversation.

get_food_log and get_daily_nutrition accept days (1–31, default 1), counting back from the inclusive end date:

get_food_log(date="yesterday")
get_nutrition_scores(date="3 days ago")
get_daily_nutrition(days=3)  # Last 3 days, including today
get_daily_nutrition(date="yesterday", days=3)  # Previous 3 complete calendar days
get_food_log(days=7)  # Recent meals, including today

For “my calories the last few days,” use get_daily_nutrition(days=3). Single-day responses retain their existing shape. Multi-day responses contain start_date, end_date, and a days list of daily results, oldest first. Returned dates are always concrete YYYY-MM-DD values.

Transport

stdio only. For remote/hosted use, the stdio server is wrapped by supergateway (see Dockerfile), which owns the HTTP listener and exposes MCP streamable-HTTP at /mcp. The server has no built-in authentication — any remote deployment must sit behind an authenticating gateway or reverse proxy.

Development

For local development, copy .env.example to .env and fill in your credentials:

cp .env.example .env
# edit .env
uv run cronometer-api-mcp

The CLI auto-loads .env on startup (dev convenience only). Real environment variables always win over .env, so production deployments and MCP client env blocks are unaffected.

How It Works

This server communicates with mobile.cronometer.com -- the same REST API used by the Cronometer Android/Flutter app. The API was reverse-engineered through:

  1. Static analysis of libapp.so (Dart AOT snapshot) from the APK to discover endpoint names
  2. Traffic interception via Frida + mitmproxy to capture exact request/response formats
  3. Trial-and-error against the live API to confirm payload shapes

The API uses two protocols:

  • v2 (POST /api/v2/*) -- JSON-body auth, used for most operations (food search, diary read/write, nutrition, fasting, macros, biometrics)
  • v3 (DELETE /api/v3/user/{id}/*) -- Header-based auth (x-crono-session), used for diary entry deletion

Recipe import is the one asynchronous operation: import_recipe returns a job id, and poll_async_result is polled until the server reports 100% progress and attaches the parsed ingredients.

Python API

You can use the client directly:

from cronometer_api_mcp.client import CronometerClient
from datetime import date

client = CronometerClient()

# Search for foods
results = client.search_food("chicken breast")

# Get food details
food = client.get_food(results[0]["id"])

# Log a serving
client.add_serving(
    food_id=food["id"],
    measure_id=food["defaultMeasureId"],
    grams=200,
)

# Get today's diary
diary = client.get_diary()

# Import a recipe from a free-text ingredient list
recipe = client.import_recipe("one hot dog\nketchup\nbun")
print(recipe["food_id"], recipe["ingredients"])

# Parse without saving, to review the matches first
preview = client.import_recipe("2 tbsp olive oil\n200g chicken", save=False)

# Get nutrition scores
scores = client.get_nutrition_scores()

License

MIT

Metadata

Release files for cronometer-api-mcp 0.2.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cronometer-api-mcp 0.2.6
File Size Uploaded Provenance
cronometer_api_mcp-0.2.6.tar.gz 86.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for cronometer-api-mcp 0.2.6
File Interpreter ABI Platform
cronometer_api_mcp-0.2.6-py3-none-any.whl Python 3 none any Details

Total release size: 124.9 kB

Release files / cronometer_api_mcp-0.2.6.tar.gz

Download URL cronometer_api_mcp-0.2.6.tar.gz
Size 86.5 kB
Tags Source
SHA-256 checksum
How to use checksums
39d1a22e24b605eb5c0f4ab7cac5fa53e9cb667f5bc2e973955996426053e2bf
BLAKE2b-256 checksum
How to use checksums
ef21ecb481c6ec1ba849bad195fc3993e113108f5319c2249ea9d058909e0186
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / cronometer_api_mcp-0.2.6-py3-none-any.whl

Download URL cronometer_api_mcp-0.2.6-py3-none-any.whl
Size 38.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eb9f853534e2eb65e8c531fbe1ea1bf1512b89059b7d2bda20fc337c7c1e534e
BLAKE2b-256 checksum
How to use checksums
648228c394006f6108b2c983c9f1b80336e1946ddc0cb70fadd14a7d822e1116
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Security for cronometer-api-mcp 0.2.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for cronometer_api_mcp-0.2.6.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page