Skip to main content

fatsecret-mcp

CI PyPI Python 3.13+ License: MIT

Log food to your FatSecret diary by talking to Claude on your phone. Claude shows you a draft first, and nothing is saved until you say yes.

https://github.com/user-attachments/assets/44dfd991-5434-47ad-8b84-bcad24415a1f

A photo of dinner, the draft Claude proposes, a "yes", the day so far, and the new entry in the FatSecret app.

fatsecret-mcp is a self-hosted MCP server. It connects Claude to your own FatSecret food diary, the one you see in the FatSecret app. Claude can read a day or a few weeks of it against your daily calorie and macro targets. It can find foods in the FatSecret catalog and draft entries from a description or a photo. Each draft shows the amounts, calories, macros, a suggested meal and how your day looks after adding it. When a packaged product isn't in the catalog, a photo of its nutrition label is enough.

One server serves a household: a few people, each signed in with their own FatSecret account. There's no public instance, so you run your own.

This project is unofficial. It is not affiliated with or endorsed by FatSecret, and it is not medical or dietary advice.

Powered by fatsecret Platform API

What you can ask

The server gives Claude five tools. You never call them yourself; you just talk.

search_foods

Finds foods in the catalog with servings that can be logged.

You: How many calories are in a cup of cooked jasmine rice?

Claude: FatSecret has "Jasmine Rice (cooked)": 1 cup (158 g) is 205 kcal, 4.3 g protein, 0.4 g fat, 44.5 g carbohydrate.

draft_entries

Proposes entries without writing anything.

You: (photo of a plate) Log this as lunch.

Claude: Here's the draft for lunch today:

  • Beef bibimbap, 1 bowl (480 g): 640 kcal, 32 g protein, 21 g fat, 80 g carbohydrate

I assumed one restaurant-sized bowl. After adding it you'll be at 1,420 of 2,200 kcal and 78 of 140 g protein. Save it?

confirm_draft

Writes the draft you approved.

You: Yes.

Claude: Saved. Beef bibimbap is in your FatSecret diary under lunch.

get_diary_day

Reads one day with its totals and what's left of your targets.

You: How much is left today?

Claude: You've had 1,420 kcal. 780 kcal are left, along with 62 g protein, 18 g fat and 95 g carbohydrate.

get_period_summary

Reads daily totals for up to 31 days.

You: How did my week go compared with the week before?

Claude: This week you averaged 2,050 kcal and 128 g protein a day; last week 2,240 kcal and 117 g protein. You went over your calorie target on two days this week, and on four the week before.

The numbers above are illustrative.

How a meal gets logged

sequenceDiagram
    actor U as You (Claude app)
    participant C as Claude
    participant S as fatsecret-mcp
    participant F as FatSecret API
    U->>C: photo + "log this as lunch"
    C->>S: search_foods
    S->>F: foods.search, food.get
    C->>S: draft_entries
    S-->>C: draft (amounts, kcal, macros, meal, the day after adding)
    C-->>U: shows the draft
    U->>C: "yes"
    C->>S: confirm_draft(draft_id)
    S->>F: food_entry.create, one per item
    S-->>C: saved entries

The draft is signed by the server and expires after thirty minutes. It can only be confirmed by the person it was made for. In Claude's connector settings, keep confirm_draft on "Needs approval" so that every write asks you first.

Products the catalog doesn't have

A free FatSecret API key reaches only the US catalog, in English. Most local and branded products aren't in it. For those, Claude asks for a photo of the nutrition label, or you type its values. The server logs the product as a stand-in: the closest catalog food, in the amount whose calories match the label, under the product's own name.

flowchart TD
    S[Claude searches the catalog] --> Q{Found?}
    Q -- yes --> E[Normal food entry]
    Q -- no --> P["You send a photo of the label<br/>or type its values"]
    P --> V[Claude reads the calories and macros]
    V --> M["The server picks the closest catalog food<br/>and sets the amount so calories match"]
    M --> N[Entry saved under the product's own name]

Calories match the label exactly; macros are close but approximate. Opening the entry's details in the FatSecret app shows the catalog food underneath. The server rejects a label whose calories don't roughly agree with its macros, which catches a misread photo or kJ taken for kcal. It doesn't remember stand-ins: next time, Claude reuses the label from the conversation or asks again.

If you log a product often, adding it once in the FatSecret app (which scans barcodes) gives you exact values there.

What it doesn't do

  • It can't look up barcodes, regional catalogs such as a Polish one, or custom foods. A free key reaches only the US catalog, so Claude searches it in English.
  • It can't edit or delete entries. Do that in the FatSecret app.
  • It doesn't track weight, exercise or recipes, only food entries.
  • It doesn't serve strangers. There's no public server, and each server has a fixed list of people.

Run your own

A household server has one Operator, the person who deploys it and adds everyone else. Each person in the household signs in to FatSecret once through the Operator, then adds the server to their own Claude account as a custom connector.

flowchart LR
    A["Anna's phone (Claude)"] --> CL[Claude connector]
    J["Jan's phone (Claude)"] --> CL
    CL -->|"each signs in with their own ID and password"| S[fatsecret-mcp on your server]
    O[Operator] -->|"add-user, check"| S
    S -->|"one FatSecret token per person"| F[FatSecret API]
    F --> D[("each person's own diary, the same as in the FatSecret app")]

You need:

  • your own FatSecret Platform API key. Register at platform.fatsecret.com; the free Basic plan is enough. Using it means accepting FatSecret's API terms. This project ships no keys;
  • a container host with HTTPS for the server, such as Railway;
  • a Claude account for each person, with custom connectors available on their plan.

The short path:

  1. Create a .env with your FatSecret key and a signing key, then run uvx --env-file .env fatsecret-mcp add-user once per person (setup).
  2. Deploy the image ghcr.io/jaronskijakub/fatsecret-mcp with those values (deploy).
  3. In Claude, add https://<your-server>/mcp as a custom connector and sign in (connector).

To try it on your own computer first, run it over stdio with Claude Code; setup covers that too. Request quotas, pacing and caching are described in limits, and the trust model in SECURITY.md.

Documentation

  • Setup: configuration, adding people, their settings, and running it locally with Claude Code.
  • Deploy: Railway, other container hosts, Docker, and building the image yourself.
  • Connector: adding the server to Claude, sign-in, and signing someone out.
  • Limits: the daily quota, pacing, search, drafts and input sizes.
  • Changelog: what changed in each version.

Report vulnerabilities through SECURITY.md, which also describes the trust model and what is stored where.

Roadmap

  • Edit and delete food entries, starting with "undo that" right after a wrong save.
  • Custom foods for users with a FatSecret Premier key, so a branded product can be logged with exact values instead of a stand-in.
  • Open Food Facts lookups for products the US catalog lacks, by name or barcode.
  • Your own recent foods. Products you often log aren't searched yet; reading them from your diary took too many API requests, so this needs another approach.
  • Remember products logged from a label, so a stand-in doesn't need the photo again. This needs persistent storage.
  • Native confirmation dialogs in Claude for saving a draft, instead of a "yes" in the chat.

Development

uv sync
uv run ruff check && uv run ruff format --check
uv run pyright
uv run pytest

The tests never call FatSecret. They replay recorded responses from tests/fixtures/fatsecret/. An opt-in smoke test reads your real diary: FATSECRET_LIVE_SMOKE=1 uv run --env-file .env pytest tests/test_live_smoke.py. Container tests are described in deploy.

To release a version, set it with uv version X.Y.Z and in both places in server.json, and give it a dated entry in CHANGELOG.md; tests/test_package.py checks that they agree. Push that commit to main and wait for CI, which publishes its image. Then push the tag vX.Y.Z. The release workflow checks that CI passed on main for that commit, builds and checks the package, adds the version tag to the commit's image, publishes the package to PyPI and creates the GitHub release from the changelog entry. In a public repository it also publishes server.json to the MCP registry.

License

MIT

Metadata

Release files for fatsecret-mcp 0.1.0

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

Source distribution (sdist)

Source distribution for fatsecret-mcp 0.1.0
File Size Uploaded Provenance
fatsecret_mcp-0.1.0.tar.gz 55.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fatsecret-mcp 0.1.0
File Interpreter ABI Platform
fatsecret_mcp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 138.9 kB

Release files / fatsecret_mcp-0.1.0.tar.gz

Download URL fatsecret_mcp-0.1.0.tar.gz
Size 55.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f80dd6d99bed9ca703434b4c05896b106fba22e9d3cfaa3ce24220fbc0537ccf
BLAKE2b-256 checksum
How to use checksums
502185b2f7d384f3d73ff53a6c2f0ad1415b8ff50c2ccfd2f4ff5bd4d7e475fd
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 20, 2026.

Transparency log

Release files / fatsecret_mcp-0.1.0-py3-none-any.whl

Download URL fatsecret_mcp-0.1.0-py3-none-any.whl
Size 83.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7925c12a7245143c8c8e2e4970eb9fe4b389ec9421224aaf10f1b7edd1e4cb63
BLAKE2b-256 checksum
How to use checksums
473af7b8f746824a5bc5a6fe183e7f66de7dedbf7adcacd87be6f19dd80ded7e
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 20, 2026.

Transparency log

Security for fatsecret-mcp 0.1.0

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 fatsecret_mcp-0.1.0.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 20, 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.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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