Atlas / MCP servers / akutishevsky / Nutrition

NutritionSAFE

mcp/akutishevsky/nutrition-2

A remote MCP server for personal nutrition tracking — log meals, track macros, and review nutrition history through conversation.

Verdict
SAFE
Grade
C
Trust score
80 /100
Exposed tools
41 24r · 12w · 5d
Transport
streamable-http
License
MIT
Stars
71
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

A remote MCP server for personal nutrition tracking — log meals with calories, macros, fiber, total and added sugar and caffeine, log water, body weight and body measurements, review nutrition history, and import an existing food diary from another app, all through conversation. Alcohol tracking is opt-in and off by default.

[Help me pay for the servers on Patreon][patreon]

[patreon]: https://patreon.com/akutishevskyi

Table of Contents

  • Quick Start
  • Demo
  • Tech Stack
  • MCP Tools
  • MCP Resources
  • Self-hosting
  • 0. Get the code
  • 1. Supabase setup
  • 2. Environment variables
  • 3. Google sign-in (optional)
  • Development
  • Testing and quality
  • Connect to Claude.ai
  • Apple Health sync
  • Troubleshooting
  • API Endpoints
  • Deploy
  • Support & security
  • Data sources
  • License

Quick Start

Already hosted and ready to use — just connect it to your MCP client:

https://nutrition-mcp.com/mcp

On Claude.ai: open Nutrition MCP in the Claude directory and click Connect (see Connect to Claude.ai below)

On first connect, sign in with Google or enter an email and password and choose Create account. Your data persists across reconnections. Trouble connecting? See Troubleshooting.

By connecting you agree to the Terms of Service; how your data is handled is in the Privacy Policy.

Switching from another tracker? See the nutrition-app alternatives — ho

Read from source at commit 053c4c6ab2bdOBSERVED · 2026-10-08
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add nutrition-mcp --env GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET} --env OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID} --env OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET} --env PATREON_ACCESS_TOKEN=${PATREON_ACCESS_TOKEN} -- npx -y [email protected]
claude-desktop
{
  "mcpServers": {
    "nutrition-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "[email protected]"
      ],
      "env": {
        "GOOGLE_CLIENT_SECRET": "${GOOGLE_CLIENT_SECRET}",
        "OAUTH_CLIENT_ID": "${OAUTH_CLIENT_ID}",
        "OAUTH_CLIENT_SECRET": "${OAUTH_CLIENT_SECRET}",
        "PATREON_ACCESS_TOKEN": "${PATREON_ACCESS_TOKEN}"
      }
    }
  }
}
03

Exposed tools (41)

24 read · 12 write · 5 destructive. Blast radius: 5 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
bulk_import_mealswrite
delete_accountdestructive
delete_body_measurementdestructive
delete_mealdestructive
delete_waterdestructive
delete_weightdestructive
export_all_dataread
get_body_measurementsread
get_current_timeread
get_goal_progressread
get_meal_patternsread
get_meals_by_dateread
get_meals_by_date_rangeread
get_meals_todayread
get_nutrition_goalsread
get_nutrition_summaryread
get_profileread
get_trendsread
get_water_by_dateread
get_water_todayread
get_weight_by_dateread
get_weight_by_date_rangeread
get_weight_todayread
get_weight_trendsread
log_body_measurementread
log_mealread
log_waterread
log_weightread
lookup_barcoderead
search_mealsread
set_alcohol_trackingwrite
set_languagewrite
set_length_unitwrite
set_nutrition_goalswrite
set_timezonewrite
set_weight_unitwrite
set_widget_displaywrite
start_meal_importwrite
update_body_measurementwrite
update_mealwrite
update_weightwrite
04

Trust audit

SAFEgrade C · trust 80/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codePASS
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (1 observation(s))
Network
declared (5 observation(s))
Shell
none-observed
Dependencies
not all pinned
Secrets in source
none-found

Findings (25)

MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
delete_account, delete_body_measurement, delete_meal, delete_water, delete_weight
Why it matters. 5 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWInventory / provenance · inv.hidden_file · CWE-1104
.prettierignore
.prettierignore
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
public/widgets/import-run.test.ts:88
const factory = new Function(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
public/widgets/import-time.test.ts:39
const factory = new Function(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
public/widgets/macros.test.ts:44
const factory = new Function(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
public/widgets/macros.test.ts:452
const api = new Function(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
public/widgets/macros.test.ts:1640
const factory = new Function(
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
public/widgets/import-run.test.ts:80
const { getWidgetHtml } = await import("../../src/widgets");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
public/widgets/import-time.test.ts:31
const { getWidgetHtml } = await import("../../src/widgets");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
public/widgets/macros.test.ts:9
import { WIDGET_STRINGS, WIDGET_STRINGS_EN } from "../../src/copy/widgets";
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
public/widgets/macros.test.ts:1632
const { getWidgetHtml } = await import("../../src/widgets");
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
public/widgets/macros.test.ts:1843
const { MEAL_BREAKDOWN_TOP_N } = await import("../../src/widgets");
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/oauth-validate.test.ts:30
["http://127.0.0.1:51789/cb", "loopback"],
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/oauth-validate.test.ts:170
"https://192.0.2.1/cb",
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/oauth-validate.test.ts:211
"http://127.0.0.1:51789/cb",
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/oauth-validate.test.ts:292
"http://127.0.0.1:1111/callback",
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
src/oauth-validate.test.ts:293
"http://127.0.0.1:2222/callback",
LOWObfuscation / stealth · obf.homoglyph · CWE-506, CWE-94
src/csv.test.ts:230
expect(normalizeHeader("B12 (μg)")).toBe(normalizeHeader("B12 (ug)"));
LOWObfuscation / stealth · obf.homoglyph · CWE-506, CWE-94
src/oauth-validate.test.ts:94
"https://clаude.ai/cb", // Cyrillic "а"
LOWObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
src/csv.test.ts:134
expect(stripBom("A")).toBe("A");
LOWObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
src/csv.test.ts:135
expect(stripBom("AB")).toBe("AB");
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@modelcontextprotocol/server, @supabase/supabase-js, hono, prettier, zod, @modelcontextprotocol/client, @types/bun
Why it matters. 7 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
CLAUDE.md:116
**Styling — reuse the shared design language.** All widgets share one look (Apple-like neutral surfaces, brand green accent, theme tokens, one compact card per widget, a donut gauge, thin metric bars,
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
CLAUDE.md:188
`src/oauth.ts` is the authorization server every MCP client signs in through, and it is the one place in this repo where a mistake hands out someone else's account: until #148, `POST /register` gave e
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
CLAUDE.md:192
- **One built-in first-party client: `HEALTH_SYNC_CLIENT` (`src/oauth-store.ts`, id `nutrition-mcp-health-sync`).** The Apple Health sync pairing signs in through the ordinary `/authorize` as this ser
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha 053c4c6ab2bdfull audit observations/trust-audit/mcp-server/akutishevsky__nutrition-2.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-08053c4c6ab2bdSAFEC80first audit
06

Questions

What is the Nutrition MCP server?

A remote MCP server for personal nutrition tracking — log meals, track macros, and review nutrition history through conversation.

What tools does Nutrition expose?

41 in total: 24 read-only, 12 that write, and 5 that can delete or overwrite (delete_account, delete_body_measurement, delete_meal, delete_water, delete_weight). Every one is listed on this page with its risk.

Is Nutrition safe to connect to an agent?

The audit found nothing in the source that contradicts what it says it does, and graded it C (80/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean server reads B. Separately from the audit: 5 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does Nutrition need?

It reads GOOGLE_CLIENT_SECRET, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, PATREON_ACCESS_TOKEN, PATREON_CLIENT_SECRET, PATREON_REFRESH_TOKEN and SUPABASE_SECRET_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Nutrition run?

It speaks streamable-http, so it runs as a service you connect to over the network. It is published on npm as nutrition-mcp at 1.28.0.

How current is this page?

The grade is for one exact copy of the source (053c4c6ab2bd), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement