Skip to main content
Glama
ikeike443
by ikeike443

fatsecret-mcp

CI

Ein persönlicher Remote-MCP-Server (Model Context Protocol), der es Claude ermöglicht, die Lebensmittel-/Rezeptdatenbank von FatSecret zu durchsuchen und dein eigenes Ernährungstagebuch, Gewicht und Trainingsprotokoll direkt im Gespräch zu lesen und zu schreiben. Bereitgestellt auf Vercels kostenlosem Hobby-Tarif. Schwesterprojekt zu fitness-mcp (Hevy) – ein MCP-Server pro Produkt, die dasselbe Authentifizierungsmuster teilen.

Lizenz

MIT

Related MCP server: Nutrition MCP

Status

  • Suche (Phase 2): implementiert – search_foods, get_food_detail, search_recipes, get_recipe_detail, find_food_by_barcode. Keine FatSecret-Benutzerautorisierung erforderlich; nur die OAuth-2.0-Client-ID/Secret aus der FatSecret-Entwicklerkonsole.

  • Tagebuch/Gewicht/Training/Profil (Phase 4): implementiert und teilweise gegen ein echtes FatSecret-Konto verifiziert – get_profile, get_food_diary und get_exercise_diary sind jetzt live bestätigt; create_exercise_entry, weight.update und find_food_by_barcode sind weiterhin unverifizierte Best-Effort-Rekonstruktionen (siehe „Was ist unverifiziert" unten für die vollständige Aufschlüsselung).

  • 3-legged-OAuth1-Setupskript (Phase 3): implementiert (scripts/fatsecret-oauth-setup.ts), noch nicht gegen ein echtes FatSecret-Konto ausgeführt.

Zwei Authentifizierungsebenen

Dieser Server sitzt zwischen Claude und FatSecret, und jede dieser beiden Beziehungen wird völlig unterschiedlich authentifiziert – das ist das Wichtigste, was man verstehen sollte, bevor man den Code anfasst.

Claude  <──①── this server (fatsecret-mcp)  ──②──>  FatSecret API

① Claude ↔ dieser Server – ein einzelnes gemeinsames Geheimnis, dasselbe Muster wie bei fitness-mcp. Claude sendet bei jeder Anfrage Authorization: Bearer <MCP_BEARER_TOKEN>; lib/auth.ts prüft es. Da Claudes Static-Header-Option noch hinter einer Beta-Sperre liegt, betreibt dieser Server auch seinen eigenen minimalen OAuth-2.1-Autorisierungsserver (lib/oauth.ts, /api/oauth/authorize, /api/oauth/token), sodass Claudes Standard-OAuth-Client-ID/Secret-Felder als immer verfügbare Fallback-Lösung funktionieren – siehe fitness-mcps README für die vollständige Begründung, die hier unverändert gilt.

Jeder Fehler auf dieser Ebene – ein falsches/fehlendes MCP_BEARER_TOKEN, eine nicht erkannte OAuth-client_id, ein falsches client_secret, schlechtes PKCE, eine nicht erlaubte redirect_uri – wird protokolliert und optional in Echtzeit alarmiert; siehe „Sicherheitsereignis-Protokollierung & Alarmierung" unten.

② dieser Server ↔ FatSecret – hier wird es komplexer als bei fitness-mcp, weil FatSecret selbst zwei verschiedene OAuth-Versionen für zwei verschiedene Arten von API-Methoden verwendet, und daran führt kein Weg vorbei – so ist die FatSecret-API entworfen, keine Entscheidung, die hier getroffen wurde:

FatSecret-Methodenkategorie

Beispielmethoden

Wie dieser Server authentifiziert

Signierte Anfrage (kein spezifischer Benutzer beteiligt)

foods.search, food.get, recipes.search, recipe.get, food.find_id_for_barcode

OAuth-2.0-Client-Credentials – lib/fatsecret/appAuth.ts ruft ein App-Level-Bearer-Token von oauth.fatsecret.com ab und cached es. Vollautomatisch; keine menschliche Interaktion nach der einmaligen Entwicklerregistrierung.

Signierte & delegierte Anfrage (liest/schreibt dein FatSecret-Konto)

food_entries.*, food_entry.*, weights.get_month, weight.update, exercise_entries.*, profile.get, foods.get_favorites

OAuth 1.0a, 3-legged, HMAC-SHA1-signiert – lib/fatsecret/oauth1.ts. FatSecret unterstützt OAuth 2.0 für diese Methoden überhaupt nicht, daher gibt es keinen Weg, OAuth1 hier zu vermeiden. Dies erfordert eine einmalige interaktive Autorisierung (Phase 3, unten), bei der du dich in einem Browser bei FatSecret anmeldest und diese App genehmigst; das resultierende Access-Token/Secret wird danach automatisch für immer wiederverwendet (siehe Hinweis unter Phase 3).

Konkret: search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode funktionieren, sobald du eine FatSecret-App registriert und FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET gesetzt hast. Jedes andere Tool benötigt zusätzlich FATSECRET_CONSUMER_KEY/FATSECRET_CONSUMER_SECRET (OAuth1 – ein anderes Anmeldedatenpaar aus derselben FatSecret-App) und FATSECRET_ACCESS_TOKEN/FATSECRET_ACCESS_TOKEN_SECRET (erhalten durch einmaliges Ausführen des Setupskripts).

Sicherheitsereignis-Protokollierung & Alarmierung

Jede fehlgeschlagene Prüfung auf Ebene ① oben (Claude ↔ dieser Server) wird über lib/securityAlert.ts gemeldet, das die folgenden Stellen absichert:

  • lib/auth.ts (verifyBearerToken) – fehlendes Bearer-Token, falsches Bearer-Token, MCP_BEARER_TOKEN nicht konfiguriert.

  • /api/oauth/authorize – nicht erkannte client_id, nicht erlaubte redirect_uri (der Open-Redirector-Fall, den isAllowedRedirectUri blockieren soll), nicht unterstützter response_type, fehlende/nicht-S256-PKCE-Challenge, OAUTH_CLIENT_SECRET nicht konfiguriert.

  • /api/oauth/token – falsches client_secret, ungültiger/abgelaufener Autorisierungscode, Code/PKCE/redirect_uri-Mismatch, MCP_BEARER_TOKEN nicht konfiguriert.

Zwei unabhängige Ebenen, sodass dies elegant degradiert:

  1. Immer protokolliert. Jeder Fehler oben schreibt eine Zeile strukturiertes JSON (event, reason, ip, userAgent, path, time) über console.error nach stderr – keine Einrichtung erforderlich, und auf Vercel erscheint dies direkt in den Funktionslogs der Bereitstellung. Das tatsächliche Bearer-Token / Client-Secret / der PKCE-Verifier-Wert wird nie einbezogen – nur Metadaten über den fehlgeschlagenen Versuch –, da ein Erkennungsmechanismus, der selbst das Geheimnis leaken könnte, das er überwacht, den Zweck verfehlen würde; lib/securityAlert.test.ts und lib/auth.test.ts prüfen dies direkt.

  2. Optionale Echtzeit-Alarmierung. Wenn SECURITY_ALERT_WEBHOOK_URL gesetzt ist (eine Slack- oder Discord-„Incoming-Webhook"-URL), wird dasselbe Ereignis auch als einzeilige Nachricht dorthin per POST gesendet, sodass ein Einbruchsversuch als Push-Benachrichtigung erscheint, statt nur sichtbar zu sein, wenn jemand zufällig den Vercel-Log-Viewer öffnet. Ein Webhook-Zustellungsfehler (abgelaufene URL, Netzwerkfehler) wird selbst als security_alert_delivery_failed protokolliert, sodass ein still kaputter Webhook nicht als „keine Versuche" gelesen wird.

Der Webhook-POST wird über Next' after() geplant, sodass er ausgeführt wird, nachdem die Antwort bereits gesendet wurde (keine zusätzliche Latenz bei der Auth-Prüfung); dies funktioniert nur innerhalb einer echten Anfrage, daher fällt es auf einen einfachen Fire-and-Forget-Aufruf zurück, wenn es direkt aufgerufen wird (z. B. aus Tests).

Dies ist bewusst ein einfaches „Alarm bei jedem Fehler"-Design, keine Schwellenwert-/ratenbasierte Alarmierung – siehe die Doc-Kommentare in lib/auth.ts/lib/securityAlert.ts für das, was ausgeklammert wurde (zahlenbasierte Schwellenwerte, Vercels eigene Plattform-Monitoring, Anmeldedatenrotation) und warum.

Verfügbare Tools

Tool

Typ

Benötigte Auth

Beschreibung

search_foods

read

OAuth2 (App)

Durchsucht FatSecrets Lebensmitteldatenbank nach Namen

get_food_detail

read

OAuth2 (App)

Vollständige Nährwerte pro Portion für ein Lebensmittel

search_recipes

read

OAuth2 (App)

Durchsucht FatSecrets Rezeptdatenbank

get_recipe_detail

read

OAuth2 (App)

Vollständige Zutaten/Anleitungen für ein Rezept

find_food_by_barcode

read

OAuth2 (App)

Löst einen GTIN-13-Barcode in eine foodId auf – benötigt den barcode-Scope, möglicherweise nur Premier

get_food_diary

read

OAuth1 (Benutzer)

Listet Ernährungstagebuch-Einträge für ein Datum

get_favorite_foods

read

OAuth1 (Benutzer)

Listet favorisierte Lebensmittel

get_most_eaten_foods

read

OAuth1 (Benutzer)

Listet am häufigsten gegessene Lebensmittel, optional nach Mahlzeit

get_recently_eaten_foods

read

OAuth1 (Benutzer)

Listet kürzlich gegessene Lebensmittel, optional nach Mahlzeit

get_weight_history

read

OAuth1 (Benutzer)

Listet Gewichtseinträge für einen Monat – möglicherweise nur Premier

get_exercise_diary

read

OAuth1 (Benutzer)

Listet Trainingseinträge für ein Datum

get_profile

read

OAuth1 (Benutzer)

Ruft die FatSecret-Profilzusammenfassung des Benutzers ab

create_food_diary_entry

write

OAuth1 (Benutzer)

Protokolliert ein Lebensmittel im Tagebuch

update_food_diary_entry

write

OAuth1 (Benutzer)

Aktualisiert einen vorhandenen Tagebucheintrag

delete_food_diary_entry

write

OAuth1 (Benutzer)

Löscht einen Tagebucheintrag

update_weight

write

OAuth1 (Benutzer)

Protokolliert/aktualisiert einen Gewichtseintrag – möglicherweise nur Premier

create_exercise_entry

write

OAuth1 (Benutzer)

Protokolliert einen Trainingseintrag

Schreib-Tools sind standardmäßig im Dry-Run-Modus

Dasselbe Design wie bei fitness-mcp: Jedes Schreib-Tool erfordert ein confirm: true-Argument. Ihre Beschreibungen weisen das aufrufende LLM an, dem Benutzer genau zu zeigen, was geschrieben wird, und zuerst eine ausdrückliche Zustimmung einzuholen. Das ist ein struktureller Anstoß, keine Garantie – dasselbe LLM, das entscheidet, ob das Tool aufgerufen wird, setzt auch confirm, und es gibt keine Trennung der Bereiche zwischen Lese-/Schreib-Tools auf der Authentifizierungsebene, sodass jeder Aufrufer mit einem gültigen MCP_BEARER_TOKEN jedes Tool aufrufen kann.

Was ist unverifiziert

Es existierte keine FatSecret-API-Registrierung, als dieses Projekt ursprünglich gebaut wurde, daher begann der Großteil als Best-Effort-Rekonstruktionen. Seitdem wurde es für einige Tools gegen ein echtes Konto geprüft – Status unten:

  • Bestätigt live, stimmt exakt mit der Implementierung überein: search_foods (foods.search), get_food_diary (food_entries.get, einschließlich der tatsächlichen Großschreibung des meal-Felds, z. B. "Breakfast").

  • Bestätigt live, nach Prüfung korrigiert: get_profile (profile.get) — eine echte Antwort enthielt height_cm, das noch nicht als Feld aufgetaucht war; jetzt hinzugefügt.

  • Bestätigt live, die tatsächliche Form ist komplexer als angenommen: get_exercise_diary (exercise_entries.get). Die Methode/Hülle ist echt, aber ein echter Eintrag, der von einer verbundenen Gesundheits-App synchronisiert wurde ({exercise_id: "184", exercise_name: "Google Health Connect", minutes: "1440", calories: "1655"} — eine aggregierte Aktivität eines ganzen Tages, kein einzelnes Training) hat kein exercise_entry_id und überhaupt kein date_int. lib/fatsecret/exercise.ts behandelt das jetzt defensiv (fehlende Felder werden zu null, kein Absturz oder irreführender erfundener Wert) und behält den vollständigen Roh-Eintrag unter raw. Noch offen: Ob ein manuell protokolliertes Training (über die FatSecret-App) eine ID/ein Datum hat, wie es die Einträge von food_entries.get haben — ungetestet.

  • Noch unverifiziert / bestmögliche Rekonstruktionen: Die Antwortform von food.find_id_for_barcode, die Parameternamen von weight.update und der Methodenname sowie die Parameter von create_exercise_entry (die obige Entdeckung zum Trainingstagebuch bedeutet, dass die gesamte Annahme des „individuell erstellbaren Eintrags“-Datenmodells möglicherweise nicht zutrifft — siehe die Warnung in lib/fatsecret/exercise.ts). Behandle diese als Ausgangspunkt, nicht als verifizierte Wahrheit.

  • Führe die untenstehende Checkliste zur manuellen Verifizierung mit einem echten Konto für alles in den beiden obigen Aufzählungspunkten durch und korrigiere alle Abweichungen, die du findest (die Unit-Tests in lib/fatsecret/*.test.ts benötigen dann entsprechende Aktualisierungen).

Einrichtung

  1. Registriere eine FatSecret Platform API-App unter https://platform.fatsecret.com/. Du erhältst:

    • Eine OAuth-2.0-Client-ID/Secret (für FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET).

    • Einen OAuth-1.0-Consumer-Key/Secret (für FATSECRET_CONSUMER_KEY/FATSECRET_CONSUMER_SECRET) — ein separates Paar aus derselben App, nicht identisch mit den obigen OAuth2-Anmeldedaten.

    • Prüfe, welche Scopes dein Plan enthält (basic / premier / barcode / ...) — weights.get_month/weight.update/find_food_by_barcode erfordern laut Berichten Premier oder die Scopes barcode/premier; bestätige dies anhand deines eigenen Plans und passe FATSECRET_OAUTH2_SCOPE bei Bedarf an.

    • Setze deine ausgehenden IP(s) auf die Whitelist (bis zu 15 Adressen/Bereiche) — die IP-Beschränkung von FatSecret ist nicht auf den Token-Endpunkt begrenzt: Gegen ein echtes Vercel-Deployment wurde bestätigt, dass der eigentliche foods.search-API-Aufruf selbst von einer nicht auf der Whitelist stehenden IP abgelehnt wurde (Fehlercode 21, „Invalid IP address detected“), selbst mit einem gültig ausgestellten Token. Sowohl der einmalige OAuth2-Token-Abruf als auch jeder einzelne Such-/Detailaufruf müssen also von einer auf der Whitelist stehenden IP stammen. Lokal ist das einfach die öffentliche IP deines Rechners (curl https://ifconfig.me). Auf Vercel, dessen Serverless-Funktionen standardmäßig keine feste ausgehende IP haben, siehe „Feste ausgehende IP für Vercel“ unten — erforderlich, bevor ein Signed-Request-Tool in Produktion funktioniert.

  2. Starte den lokalen Entwicklungsserver einmal, um die Suche zu testen (Phase 2 benötigt nur Schritt 1):

    npm install
    cp .env.example .env.local   # fill in FATSECRET_CLIENT_ID/SECRET + the MCP_BEARER_TOKEN/OAuth trio
    vercel dev
  3. Führe das einmalige 3-legged-OAuth1-Setup aus (für jedes Tool außer den 5 Such-/Detail-Tools erforderlich) — siehe Phase 3 unten.

  4. Stelle auf Vercel bereit — siehe Bereitstellung unten, aber lies zuerst „Feste ausgehende IP für Vercel“.

Feste ausgehende IP für Vercel

Vercels Serverless-Funktionen haben keine feste ausgehende IP, was angesichts der obigen Erkenntnis ein Problem darstellt — jeder search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode-Aufruf, nicht nur der Token-Abruf, muss von einer auf der Whitelist stehenden IP stammen. Ohne dies funktionieren diese fünf Tools lokal einwandfrei (deine Rechner-IP ist die, die du auf die Whitelist gesetzt hast), schlagen aber in Produktion mit FatSecret API error 21: Invalid IP address detected fehl.

Lösung: Leite diese Anfragen über einen HTTP-Proxy mit fester IP. Dieser Server unterstützt Fixie standardmäßig:

  1. Melde dich bei usefixie.com an — der kostenlose tricycleFree-Plan (500 Anfragen/100 MB pro Monat, 0 $) reicht für den persönlichen Gebrauch, da dies nur den Signed-Request-Verkehr von FatSecret trägt, nicht deine gesamte App. Beachte, dass das Anfragekontingent des Plans eine echte Einschränkung ist, anders als ein reines App-Ratenlimit — wenn du viel suchst, beobachte die Nutzung und upgrade (commuter, 5 $/Monat/2.500 Anfragen), wenn du in die Nähe kommst.

  2. Kopiere die Proxy-URL, die Fixie dir gibt (http://fixie:<password>@<host>:<port>).

  3. Setze sie als FIXIE_URL — in .env.local für lokale Tests über den Proxy und als Vercel-Umgebungsvariable für die Produktion. Lasse sie für die normale lokale Entwicklung ungesetzt (wo deine eigene IP bereits direkt auf der Whitelist steht) — lib/fatsecret/appAuth.ts leitet nur dann über den Proxy, wenn FIXIE_URL vorhanden ist.

  4. Setze die feste IP von Fixie (auf deinem Fixie-Dashboard angezeigt) in der FatSecret-Entwicklerkonsole auf die Whitelist, zusätzlich zu (nicht anstelle von) allen IP(s), die du für die lokale Entwicklung auf die Whitelist gesetzt hast.

Kein anderer Server-zu-FatSecret-Verkehr läuft über diesen Proxy — die OAuth1-Anfragen (Signed & Delegated) in lib/fatsecret/oauth1.ts sind nicht IP-beschränkt, daher benötigen Tagebuch-/Gewichts-/Trainings-/Profil-Tools FIXIE_URL überhaupt nicht.

Lokale Entwicklung

npm install
cp .env.example .env.local   # fill in real values
vercel dev

Smoke-Test (ersetze $MCP_BEARER_TOKEN):

curl -X POST http://localhost:3000/api/mcp \
  -H "Authorization: Bearer $MCP_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Sollte die 17 oben genannten Tools zurückgeben. Eine Anfrage mit fehlendem/falschem Token sollte 401 erhalten.

Phase 3: einmaliges 3-legged-OAuth1-Setup

Jedes Tool außer search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode benötigt ein OAuth1-Zugriffstoken/Secret, das an dein FatSecret-Konto gebunden ist. Hole es einmal:

npm run fatsecret:oauth-setup

Dies (scripts/fatsecret-oauth-setup.ts) wird:

  1. Ein nicht autorisiertes Request-Token von FatSecret anfordern.

  2. Eine Autorisierungs-URL ausgeben — öffne sie, melde dich bei FatSecret an und genehmige. FatSecret zeigt einen Bestätigungscode.

  3. Dich auffordern, diesen Code einzufügen, und ihn dann gegen ein dauerhaftes Zugriffstoken/Secret eintauschen.

  4. FATSECRET_ACCESS_TOKEN/FATSECRET_ACCESS_TOKEN_SECRET in .env.local schreiben.

Füge dann auch diese beiden Werte zu den Umgebungsvariablen von Vercel hinzu (.env.local wird nie bereitgestellt) — siehe Bereitstellung unten.

Laut FatSecret-Dokumentation läuft dieses Zugriffstoken nicht ab. Falls es jemals widerrufen wird (z. B. wenn du den App-Zugriff aus deinen FatSecret-Kontoeinstellungen entfernst), führe einfach das Skript erneut aus, um ein neues zu erhalten — siehe das derive()-Muster von fitness-mcp im Geiste: Ein verlorenes Zugriffsdokument ist hier keine Katastrophe, sondern eine Ein-Befehl-Korrektur, nur diesmal interaktiv statt einer deterministischen Neuableitung.

Generieren der Claude-zugewandten Geheimnisse aus einer einprägsamen Passphrase

MCP_BEARER_TOKEN, OAUTH_CLIENT_ID und OAUTH_CLIENT_SECRET (Schicht ① — Claude ↔ dieser Server, unabhängig von den obigen FatSecret-Anmeldedaten) können alle deterministisch aus einer einzigen Master-Passphrase abgeleitet werden, sodass der Verlust der gespeicherten Werte keine Katastrophe ist — leite sie einfach neu ab:

derive() {
  if [ -z "$MASTER_PASSPHRASE" ]; then
    printf "Master passphrase: "
    read -rs MASTER_PASSPHRASE
    echo
  fi
  echo -n "$1" | openssl dgst -sha256 -hmac "$MASTER_PASSPHRASE" -hex | awk '{print $2}'
}

derive "fatsecret-mcp:bearer-token"        # → MCP_BEARER_TOKEN
derive "fatsecret-mcp:oauth-client-id"     # → OAUTH_CLIENT_ID
derive "fatsecret-mcp:oauth-client-secret" # → OAUTH_CLIENT_SECRET

Die Label-Strings sind nicht geheim (sie können sicher in dieser README bleiben) — nur die Passphrase ist es. Das erneute Ausführen von derive mit derselben Passphrase reproduziert immer dieselben Werte. Dies gilt nicht für die FatSecret-seitigen Anmeldedaten (FATSECRET_CLIENT_ID/SECRET, FATSECRET_CONSUMER_KEY/SECRET, FATSECRET_ACCESS_TOKEN/SECRET) — diese stammen aus der FatSecret-Entwicklerkonsole und dem OAuth1-Setup-Skript, nicht aus dieser Passphrase.

Testen

Drei Ebenen, alle in CI (.github/workflows/ci.yml) bei jedem Push/PR ausgeführt — keine erfordert echte FatSecret-Geheimnisse, daher funktionieren sie in einem öffentlichen Repository gleich:

npm run test        # unit + integration (vitest) — pure logic, plus the real Next.js
                     # route handler exercised with fetch mocked
npm run build
npm run test:e2e     # starts a real `next start` server and hits it over real HTTP
                      # (node's built-in test runner, no extra dependency)
  • Unit (lib/**/*.test.ts): Bearer-Token-Verifizierung, OAuth2.1-Code-Signierung/PKCE/Redirect-URI-Allowlisting (RFC-7636-Testvektor enthalten), FatSecret-OAuth2-Client-Credentials-Token-Abruf/Cache/Aktualisierung (lib/fatsecret/appAuth.test.ts), OAuth1-HMAC-SHA1-Signierung, gegen eine unabhängige Neuimplementierung geprüft (lib/fatsecret/oauth1.test.ts), und jede Antwortform-Normalisierung in lib/fatsecret/*.ts (Einzelobjekt-vs-Array, numerischer-String-vs-Zahl, Eigenheiten leerer Antworten).

  • Integration (test/integration/*.test.ts): Der echte app/api/mcp/route.ts-Handler, der mit den echten lib/fatsecret/*-Modulen verdrahtet ist, wobei nur fetch gemockt ist, deckt sowohl die OAuth2- (Signed Request) als auch die OAuth1- (Signed & Delegated) Tool-Pfade ab, sowie Bestätigungs-Gating bei jedem Schreib-Tool; die echten /api/oauth/authorize//api/oauth/token-Routen; die .well-known-OAuth-Metadaten-Routen.

  • E2E (test/e2e/*.e2e.test.mjs): Startet den Produktions-Build und prüft über echtes HTTP — Health-Check, 401 bei falscher/fehlender Authentifizierung, tools/list gibt alle 17 Tools zurück, OAuth-Discovery-Metadaten und einen vollständigen Autorisierungscode- + PKCE-Roundtrip. Übt keine echten FatSecret-Daten aus (CI hat absichtlich keine echten Anmeldedaten).

Manuelle Verifizierung mit einem echten FatSecret-Konto

CI berührt niemals echte FatSecret-Daten, und — gemäß „Was ist unverifiziert“ oben — wurden einige Annahmen dieses Servers über die genauen Antwortformen von FatSecret überhaupt nicht gegen ein echtes Konto geprüft. Nach der Registrierung und dem Ausführen des OAuth1-Setup-Skripts arbeite diese Checkliste durch und korrigiere alle Abweichungen, die du findest:

  1. Setze echte FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET in .env.local, führe vercel dev aus und rufe search_foods mit einer echten Abfrage auf — erledigt, gegen ein echtes Konto bestätigt. Tue dies weiterhin für get_food_detail, falls du es noch nicht getan hast — bestätige, dass es vernünftige Nährwerte zurückgibt.

  2. Rufe search_recipes und get_recipe_detail ähnlich auf. Noch offen.

  3. Wenn dein Plan den barcode-Scope enthält, rufe find_food_by_barcode mit dem Barcode eines echten Produkts auf und bestätige, dass die Antwortform mit RawFindIdForBarcodeResponse in lib/fatsecret/foods.ts übereinstimmt — korrigiere sie, falls nicht. Noch offen.

  4. Führe npm run fatsecret:oauth-setup aus und rufe dann get_profile und get_food_diary auf — erledigt. get_food_diary stimmte exakt überein; get_profile fehlte heightCm, jetzt korrigiert — siehe „Was ist unverifiziert“ oben.

  5. Rufe create_food_diary_entry mit confirm: true und einem offensichtlichen Wegwerf-Eintrag auf, dann get_food_diary für dasselbe Datum und bestätige, dass es mit dem richtigen Lebensmittel/Portion/Menge/Mahlzeit erscheint. Dann update_food_diary_entry und delete_food_diary_entry — bestätige, dass jeder Roundtrip funktioniert. Noch offen — beachte, dass meal von get_food_diary großgeschrieben zurückkommt ("Breakfast"); es lohnt sich, zu überprüfen, ob create_food_diary_entry/update_food_diary_entry dieselbe Großschreibung beim Schreiben akzeptieren (oder welche Großschreibung FatSecret auf der Schreibseite tatsächlich erwartet), bevor du annimmst, dass es in Ordnung ist.

  6. Wenn dein Plan Gewichtsverfolgung enthält, rufe update_weight mit confirm: true auf und bestätige, dass get_weight_history es widerspiegelt. Noch offen.

  7. create_exercise_entry und get_exercise_diary sind das am wenigsten verifizierte Paar in dieser Codebasis. Die Methode/Hülle von get_exercise_diary ist jetzt als echt bestätigt, hat aber offenbart, dass das Datenmodell des Trainingstagebuchs komplexer ist als angenommen (siehe „Was ist unverifiziert“ oben) — bevor du create_exercise_entry vertraust, protokolliere zuerst ein Training manuell in der FatSecret-App und überprüfe get_exercise_diary erneut, um zu sehen, ob ein manueller Eintrag ein exercise_entry_id/date_int hat, wie es Lebensmitteleinträge tun; das zeigt dir, ob „individuell erstellbarer Eintrag“ hier überhaupt das richtige Modell ist, bevor du create_exercise_entry selbst gegen echte Daten versuchst.

  8. Committe niemals echte FatSecret-Anmeldedaten und führe diese Checkliste niemals in CI aus.

Umgebungsvariablen

Variable

Zweck

FATSECRET_CLIENT_ID / FATSECRET_CLIENT_SECRET

OAuth-2.0-Client-Anmeldedaten — Signed-Request-Methoden (Such-/Detail-Tools)

FATSECRET_OAUTH2_SCOPE

Optional. Durch Leerzeichen getrennte OAuth2-Scope(s), Standard basic. Bei Bedarf barcode/premier hinzufügen

FATSECRET_FOOD_GET_METHOD

Optional. Standardmäßig food.get.v4; überschreiben (z. B. food.get), wenn Ihr Tarif keinen v4-Zugriff hat

FIXIE_URL

Optional. HTTP-Proxy-URL mit fester IP (http://fixie:<password>@<host>:<port>) für den OAuth2-Token-Abruf und jeden Signed-Request-Aufruf — auf Vercel erforderlich, da es standardmäßig keine feste ausgehende IP hat. Siehe „Fixed outbound IP for Vercel" oben. Für die lokale Entwicklung nicht setzen.

FATSECRET_CONSUMER_KEY / FATSECRET_CONSUMER_SECRET

OAuth-1.0-Consumer-Key/-Secret — signiert sowohl das einmalige Setup-Skript als auch jeden Signed- und Delegated-Aufruf

FATSECRET_ACCESS_TOKEN / FATSECRET_ACCESS_TOKEN_SECRET

OAuth-1.0-Zugriffstoken/-geheimnis für Ihr FatSecret-Konto — erhalten über npm run fatsecret:oauth-setup (Phase 3)

MCP_BEARER_TOKEN

Gemeinsames Geheimnis, das dieser Server bei jeder Anfrage verlangt, sowie das access_token, das unser OAuth-Flow ausstellt

OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET

Anmeldedaten für den eigenen minimalen OAuth-Autorisierungsserver dieses Servers

OAUTH_ALLOWED_REDIRECT_HOSTS

Optional. Kommagetrennte Zulassungsliste für die redirect_uri von /api/oauth/authorize. Standardmäßig claude.ai,claude.com

SECURITY_ALERT_WEBHOOK_URL

Optional. Eingehende Slack-/Discord-Webhook-URL für Echtzeitwarnungen bei Authentifizierungsfehlern — siehe „Security event logging & alerting" oben. Fehler werden unabhängig davon, ob dies gesetzt ist, immer in stderr protokolliert

Setzen Sie diese in den Umgebungsvariablen des Vercel-Projekts (Production + Preview). Übertragen Sie niemals echte Werte — .env.example dokumentiert nur die Namen.

Bereitstellung

  1. vercel link

  2. vercel env add FATSECRET_CLIENT_ID (für jede Variable in der obigen Tabelle wiederholen, für die Sie einen Wert haben — mindestens FATSECRET_CLIENT_ID/SECRET, MCP_BEARER_TOKEN, OAUTH_CLIENT_ID/SECRET; FIXIE_URL gemäß „Fixed outbound IP for Vercel" oben hinzufügen — in der Praxis erforderlich, nicht optional; das Paar FATSECRET_CONSUMER_*/FATSECRET_ACCESS_TOKEN* hinzufügen, sobald Sie das OAuth1-Setup-Skript ausgeführt haben)

  3. Setzen Sie die Node.js-Version des Vercel-Projekts auf 22.19 oder neuer (Projekt → Einstellungen → Allgemein → Node.js-Version, oder wo auch immer das aktuelle Vercel-Dashboard sie platziert) vor dem Bereitstellen — d. h. vor Schritt 4 unten. Die undici@8-Abhängigkeit dieses Servers (für den Fixie-Proxy verwendet — siehe „Fixed outbound IP for Vercel" oben) deklariert "engines": {"node": ">=22.19.0"}, und das eigene engines-Feld in package.json dokumentiert dieselbe Anforderung — aber keines von beiden erzwingt auf Vercel von sich aus etwas, sodass ein Projekt, das weiterhin an einer älteren Node-Version (z. B. 20.x) festhält, „erfolgreich" bereitgestellt wird und dann zur Laufzeit fehlschlägt.

  4. Verbinden Sie dieses GitHub-Repository im Vercel-Dashboard für automatische Bereitstellung bei Push auf main, oder führen Sie vercel --prod manuell aus.

  5. Notieren Sie die bereitgestellte URL (prüfen Sie Projekt → Einstellungen → Domains — die Produktions-URL dieses Projekts war die nicht beanspruchte https://fatsecret-mcp.vercel.app, aber das ist Vercels gemeinsamer Namensraum, also gehen Sie nicht davon aus, dass sie für einen Fork frei sein wird).

  6. Nehmen Sie Fixies feste IP in die Zulassungsliste auf in der FatSecret-Entwicklerkonsole (siehe „Fixed outbound IP for Vercel" oben) — dies ist der Schritt, der in der Produktion am wahrscheinlichsten Probleme bereitet, da ohne ihn search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode alle mit FatSecret API error 21 fehlschlagen.

Mit Claude verbinden

Benutzerdefinierte Connectors können nur über claude.ai (Web) oder die Desktop-App hinzugefügt werden — nicht über die mobile App. Einmal dort hinzugefügt, sind sie automatisch auch mobil nutzbar.

  1. Auf claude.ai: Einstellungen → Connectors → Benutzerdefinierten Connector hinzufügen.

  2. Name: FatSecret. URL: https://<your-deployment>/api/mcp.

  3. Wenn Ihr Konto die Beta-Funktion „Request headers" hat: Fügen Sie dort Authorization: Bearer <MCP_BEARER_TOKEN> hinzu und fahren Sie mit Schritt 5 fort.

  4. Andernfalls öffnen Sie die erweiterten Einstellungen und füllen Sie OAuth Client ID / OAuth Client Secret mit den in Vercel gesetzten Werten OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET aus. Claude erkennt die Endpunkte /authorize und /token automatisch über die .well-known-Metadaten dieses Servers.

  5. Speichern. Claude sollte die 17 Tools oben auflisten.

Versuchen Sie zu fragen: „バナナのカロリーを教えて" (sagen Sie mir die Kalorien einer Banane) oder „今日の朝食にバナナを1本記録して" (eine Banane für das heutige Frühstück protokollieren — sobald Phase 3/4 eingerichtet und verifiziert sind).

Danksagungen

Das Design des 3-legged-OAuth1-Flows wurde von fcoury/fatsecret-mcp (MIT) inspiriert, das den OAuth-Flow selbst als MCP-Tools bereitstellt; dieses Projekt führt ihn stattdessen einmalig als eigenständiges Setup-Skript (scripts/fatsecret-oauth-setup.ts) aus, da es für ein einzelnes persönliches FatSecret-Konto und nicht für die Nutzung durch mehrere Benutzer ausgelegt ist. Es wurde kein Code daraus kopiert.

Related MCP Connectors

Related MCP Servers