Skip to main content
Glama

๐Ÿฝ๏ธ foodos-mcp

Big batch. Different appetites. Macros that add up. โœจ

Turn recipes into traceable nutrition numbers, cooked-weight calculations, and portions that fit each eater โ€” all through the Model Context Protocol (MCP).

Your AI assistant handles the conversation. foodos-mcp handles the math. ๐Ÿงฎ

LLMs can help you find dinner, but they can also guess gram weights, invent macros, or split a batch in half when everyone needs a different portion. This server makes those calculations deterministic and auditable, from the first ingredient to the last lunchbox.

โœจ Meet your meal-prep math engine

  • ๐Ÿ”Ž Know where every number came from. Macro values trace to a USDA food ID, an Open Food Facts barcode, or data you supplied.

  • โš–๏ธ Weigh it cooked. Count it correctly. Turn raw ingredient totals into macros per 100 g of the finished batch.

  • ๐Ÿ› One batch, different portions. Size a serving by a target, a fixed weight, or whatever is left.

  • ๐Ÿ“ฆ Give leftovers a plan. Keep track of portions for tonight and boxes for later.

  • ๐Ÿ›‘ Keep guesses off the plate. Ambiguous food lookups return candidates for you to choose from.

๐Ÿฅ• Raw ingredients โ†’ ๐Ÿงฎ Batch macros โ†’ ๐Ÿณ Cooked weight
                                            โ†“
                                  Macros per 100 g cooked
                                            โ†“
                              ๐Ÿฝ๏ธ Portions sized for each eater
                                            โ†“
                                  ๐Ÿ“ฆ Leftovers & meal prep

One eater needs enough protein to finish their daily target. Another takes 180 g off the scale. A third takes what is left. Tuesday's lunch gets a box, too. Equal portions are optional. Getting the math right is the whole point. ๐Ÿ™Œ

๐Ÿš€ Get started ยท ๐Ÿ— See the math ยท ๐Ÿงฐ Explore the tools ยท ๐Ÿ› ๏ธ Contribute

Related MCP server: nutrition-mcp-server

๐Ÿš€ Quick start

npx foodos-mcp            # stdio, for a local client
npx foodos-mcp --transport http --port 3000

Node 22.12 or newer. You need a free USDA API key, which takes about a minute to get at api.data.gov/signup.

๐Ÿ–ฅ๏ธ Connect to Claude Desktop

Add this to claude_desktop_config.json, then restart Claude Desktop.

{
  "mcpServers": {
    "foodos": {
      "command": "npx",
      "args": ["-y", "foodos-mcp"],
      "env": {
        "FDC_API_KEY": "your-key-here",
        "FOODOS_CONTACT": "you@example.com"
      }
    }
  }
}

FOODOS_CONTACT goes in the User-Agent when the server reads Open Food Facts, which their terms ask for. Everything works without it; you are just anonymous.

๐Ÿ— A batch in action

Letโ€™s roast 800 g of chicken and follow the numbers all the way to the plate. Every step is checkable. ๐Ÿ”

1. ๐Ÿ”Ž Find the food. searchFood with "chicken breast raw" returns candidates from USDA. Pick one; the model should show you the list rather than choose. Here it is fdcId 2646170, "Chicken, breast, boneless, skinless, raw".

2. ๐Ÿงฌ Get its macros. getFoodMacros returns, per 100 g:

per 100 g

Protein

22.525 g

Fat

1.934 g

Carbohydrate

0 g

Energy

106.034 kcal

It also reports energySource: "atwater_general_2047". Foundation foods carry no plain energy nutrient at all, only the two Atwater values, and the server tells you which one it used rather than leaving you to wonder.

3. ๐Ÿงฎ Total the batch. computeBatchMacros with 800 g of it: 180.2 g protein, 15.5 g fat, 848 kcal.

4. ๐Ÿณ Weigh it after cooking. You roast it and the tray comes out at 600 g. setCookedYield with rawG: 800, cookedG: 600 gives a yield factor of 0.75 and, per 100 g cooked: 30 g protein, 2.6 g fat, 141 kcal.

5. ๐Ÿฝ๏ธ Serve it up. portionBatch with two rules, one fixed weight and one remainder:

Eater

Rule

Weight

Protein

Energy

A

fixed 180 g

180 g

54.1 g

254 kcal

B

remainder

420 g

126.1 g

594 kcal

54.06 plus 126.14 is 180.2, which is the batch. The arithmetic runs at full precision from end to end and only the presentation is rounded, so the reconciliation is exact even where two rounded figures are each a tenth off.

๐ŸŽฏ Want a portion that fills a target? Change A's rule to solveForRemaining and give A a daily protein target of 150 g with 100 g already eaten. A gets the 166 g that carries the remaining 50 g of protein, and the response says bindingConstraint: "proteinG" along with where fat and energy landed. If that portion blows A's fat target, the response says so in the residuals rather than leaving you to notice.

๐Ÿƒ Try it yourself: examples/worked-example.ts runs this against the live API with your own key.

๐Ÿงฐ The toolbox

๐Ÿ“– Read a recipe. parseRecipe pulls the schema.org data a page publishes for machines. parseIngredientLine splits one line into its parts and flags what is ambiguous, so "1 medium onion" comes back as a size descriptor rather than as 150 g.

๐Ÿ”Ž Look up nutrition. searchFood, getFoodMacros, lookupBarcode, toGrams.

๐Ÿงฎ Calculate the batch. computeBatchMacros, setCookedYield.

๐Ÿฝ๏ธ Portion your plates. portionBatch, the reason this repository exists.

๐Ÿ›’ Plan the next batch. planBatchSize, scaleRecipe, shoppingList.

๐Ÿ“š Peek under the hood. foodos://yield-factors and foodos://densities expose the bundled tables so you can see exactly what a calculation was based on. foodos://rate-limit-status shows how much of the hourly budget is left.

๐Ÿ’ฌ Follow the guided workflow. portionABatch walks a client through the whole chain, from a URL to portions on plates.

๐ŸŒ Ingredients deserve sources. So do numbers.

Hereโ€™s where the data comes from, along with the licensing and caching considerations behind the integrations.

Source

Verdict

Why

USDA FoodData Central

Primary nutrition source

US public domain under CC0 1.0. Free key from api.data.gov. No caching restriction, so this server caches aggressively.

Open Food Facts

Secondary, for packaged goods and barcodes

Open data under the ODbL, contents under the DbCL. Their terms ask for a descriptive User-Agent with a contact address, which this server sends.

Spoonacular

Not integrated

Their terms cap caching at about an hour and then require deletion. That is incompatible with a local store, and a local store is what makes the rate limit survivable.

Edamam

Not integrated

Their terms prohibit automated programmatic requests intended to collect or save data. An MCP server is exactly that.

Cooking yields come from the USDA Table of Cooking Yields for Meat and Poultry, Release 2 (CC0), plus rows transcribed by hand from Agriculture Handbook 102 (1975, public domain) for rice, pasta, lentils and oats, each citing its page. Densities are derived from the USDA SR Legacy bulk export, a 6 MB public-domain download that needs no API key, with each row citing the food and portion it came from. A cup of flour is 125 g and a cup of honey is 339 g, which is why volume never converts to weight without knowing the ingredient.

Rice roughly triples in weight when cooked and lentils nearly do. A yield factor is not always below 1, and treating it as though it were would be wrong for half a kitchen.

๐Ÿšฆ Keep your API budget happy

FoodData Central runs behind api.data.gov: 1,000 requests an hour per key, on a rolling window, with a 429 when you go over. A single recipe with fifteen ingredients can burn thirty calls between searching and looking up, so this is a real ceiling rather than a theoretical one.

Hereโ€™s how the server keeps the budget visible:

  • A local counter refuses the call before it leaves the process when the budget is spent, and tells you when it frees up.

  • Response headers are authoritative. If USDA says 40 requests remain, the local count is corrected to match, because a key shared with another client is further along than this process can know.

  • The default budget is 800, deliberately under the real 1,000, so a second client does not push you into a 429.

  • Nothing queues, sleeps or retries. Only you know whether the rest of the work is worth what is left.

  • Cache hits never count. Lookups are cached for a month, which is allowed without reservation because the data are public domain.

Check foodos://rate-limit-status before a big batch. Set FDC_HOURLY_BUDGET to change the ceiling.

The real answer, when this becomes a problem, is that USDA publishes complete monthly exports of about 6 GiB. A local copy takes the API out of the hot path entirely. That is the v0.2 plan; there is a TODO(bulk-import) in the client pointing at it.

DEMO_KEY works for a first smoke test and is capped at ten requests an hour, which you will hit almost immediately. It is never used as a fallback in code.

โš™๏ธ Make it yours

Variable

Default

What it does

FDC_API_KEY

none

Required for anything that reads USDA data. No default key ships in this repository.

FDC_HOURLY_BUDGET

800

Requests an hour before the server refuses to make more.

FOODOS_CONTACT

repository URL

Contact address sent in the User-Agent, as Open Food Facts asks.

FOODOS_CACHE_DIR

platform cache directory

Where cached lookups live.

FOODOS_LOG_LEVEL

info

debug, info, warn, error or silent. Always goes to stderr, because stdout carries the protocol.

โ˜๏ธ Run it remotely

foodos-mcp --transport http --host 127.0.0.1 --port 3000 --allowed-hosts foodos.example.com

The endpoint is POST /mcp, and GET /healthz answers for a load balancer. It runs stateless, so there is no session affinity to arrange.

There is no authentication in this server, on purpose. Terminate TLS and auth at the reverse proxy and keep the server bound to loopback:

location /mcp {
    proxy_pass http://127.0.0.1:3000/mcp;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header Connection "";
    proxy_buffering off;          # streamable HTTP sends server-sent events
    proxy_read_timeout 300s;
}

Passing --allowed-hosts turns on DNS rebinding protection for the hosts you name.

๐Ÿงญ What belongs on the menu

foodos-mcp focuses on recipe and portion calculations. It provides numbers, with no health advice, diet recommendations, or judgments about your plate.

There are no accounts or built-in authentication. The server reads two public food data sources, caches lookups locally, and does the arithmetic.

๐Ÿ› ๏ธ Build with us

pnpm install
pnpm check        # biome, tsc and vitest
pnpm test:coverage
pnpm build

The test suite runs entirely offline. Every HTTP request is intercepted, and an unhandled one fails the run, so a forgotten network call cannot reach USDA from CI.

Ready to dig in? Read CONTRIBUTING.md before opening a pull request. ๐Ÿง‘โ€๐Ÿณ

๐Ÿ“œ License

MIT licensed. Fork it, explore it, and build something delicious. See LICENSE.

USDA FoodData Central data are in the public domain. U.S. Department of Agriculture, Agricultural Research Service. FoodData Central, fdc.nal.usda.gov. Open Food Facts data are available under the Open Database License.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides access to a comprehensive food database with 300,000+ items, enabling nutritional data lookups, food searches, and barcode scanning with all processing happening locally for privacy and speed.
    205
    MIT