fatsecret-mcp
fatsecret-mcp
Claude が FatSecret の食品・レシピデータベースを検索し、自分のフードダイアリー、体重、エクササイズログを会話の中で直接読み書きできる、個人用のリモート MCP(Model Context Protocol)サーバーです。Vercel の無料 Hobby プランにデプロイされています。fitness-mcp(Hevy)の姉妹プロジェクトで、製品ごとに 1 つの MCP サーバーを持ち、同じ認証パターンを共有しています。
ライセンス
Related MCP server: Nutrition MCP
ステータス
検索(フェーズ 2): 実装済み —
search_foods、get_food_detail、search_recipes、get_recipe_detail、find_food_by_barcode。FatSecret のユーザー認可は不要で、FatSecret の開発者コンソールから取得した OAuth 2.0 の Client ID/Secret のみが必要です。ダイアリー/体重/エクササイズ/プロフィール(フェーズ 4): 実装済み、かつ実際の FatSecret アカウントで部分的に検証済み —
get_profile、get_food_diary、get_exercise_diaryはライブで確認済みです。create_exercise_entry、weight.update、find_food_by_barcodeはまだ未検証のベストエフォート再構築です(詳細な内訳は下記「未検証のもの」を参照)。3-legged OAuth1 セットアップスクリプト(フェーズ 3): 実装済み(
scripts/fatsecret-oauth-setup.ts)、実際の FatSecret アカウントではまだ実行していません。
2 つの認証レイヤー
このサーバーは Claude と FatSecret の間に位置し、その 2 つの関係はそれぞれ完全に異なる方法で認証されます。コードに触れる前に理解すべき主要な点です。
Claude <──①── this server (fatsecret-mcp) ──②──> FatSecret API① Claude ↔ このサーバー — 単一の共有シークレットで、fitness-mcp と同じパターンです。Claude はすべてのリクエストで Authorization: Bearer <MCP_BEARER_TOKEN> を送信し、lib/auth.ts がそれをチェックします。Claude の静的ヘッダーオプションはまだベータ版で制限されているため、このサーバーは独自の最小限の OAuth 2.1 認可サーバー(lib/oauth.ts、/api/oauth/authorize、/api/oauth/token)も実行し、Claude の標準的な OAuth Client ID/Secret フィールドが常に利用可能なフォールバックとして機能するようにしています。詳細な理由は fitness-mcp の README を参照してください。ここでも同じことが当てはまります。
このレイヤーでのすべての失敗 — 不正な/欠落した MCP_BEARER_TOKEN、認識されない OAuth client_id、誤った client_secret、不正な PKCE、許可されていない redirect_uri — はログに記録され、オプションでリアルタイムにアラートが送信されます。下記の「セキュリティイベントのログ記録とアラート」を参照してください。
② このサーバー ↔ FatSecret — ここが fitness-mcp よりも複雑な点です。なぜなら FatSecret 自体が2 種類の API メソッドに対して 2 つの異なる OAuth バージョンを使用しており、これを回避する方法はないからです。これは FatSecret の API の設計であり、ここでの選択ではありません。
FatSecret メソッドカテゴリ | 例となるメソッド | このサーバーが認証する方法 |
署名付きリクエスト(特定のユーザーが関与しない) |
| OAuth 2.0 クライアントクレデンシャル — |
署名付き&委任リクエスト(あなたの FatSecret アカウントを読み書きする) |
| OAuth 1.0a、3-legged、HMAC-SHA1 署名 — |
具体的には、search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode は、FatSecret アプリを登録して FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET を設定すればすぐに動作します。他のすべてのツールは、さらに FATSECRET_CONSUMER_KEY/FATSECRET_CONSUMER_SECRET(OAuth1 — 同じ FatSecret アプリからの別のクレデンシャルペア)と、FATSECRET_ACCESS_TOKEN/FATSECRET_ACCESS_TOKEN_SECRET(セットアップスクリプトを一度実行して取得)が必要です。
セキュリティイベントのログ記録とアラート
上記のレイヤー①(Claude ↔ このサーバー)でのすべての失敗チェックは lib/securityAlert.ts を通じて報告され、以下の箇所をゲートします。
lib/auth.ts(verifyBearerToken)— ベアラートークンの欠落、誤ったベアラートークン、MCP_BEARER_TOKENが未設定。/api/oauth/authorize— 認識されないclient_id、許可されていないredirect_uri(オープンリダイレクタのケースをブロックするためにisAllowedRedirectUriが存在)、サポートされていないresponse_type、欠落または非 S256 の PKCE チャレンジ、OAUTH_CLIENT_SECRETが未設定。/api/oauth/token— 誤ったclient_secret、無効または期限切れの認可コード、コード/PKCE/redirect_uri の不一致、MCP_BEARER_TOKENが未設定。
2 つの独立したレイヤーがあるため、これはグレースフルに劣化します。
常にログ記録。上記の各失敗は、構造化 JSON の 1 行(
event、reason、ip、userAgent、path、time)をconsole.errorでstderrに書き込みます。セットアップは不要で、Vercel ではそのままデプロイの関数ログに表示されます。実際のベアラートークン、クライアントシークレット、PKCE ベリファイアの値は決して含まれません — 監視対象のシークレット自体を漏らす可能性のある検出メカニズムは意味をなさないため、失敗した試行に関するメタデータのみが含まれます。lib/securityAlert.test.tsとlib/auth.test.tsがこれを直接検証しています。オプションのリアルタイムアラート。
SECURITY_ALERT_WEBHOOK_URLが設定されている場合(Slack または Discord の「incoming webhook」URL)、同じイベントが 1 行のメッセージとしてそこにも POST され、侵入の試みがプッシュ通知として表面化します。誰かがたまたま Vercel のログビューアを開いたときだけ見えるのではありません。Webhook の配信失敗(URL の期限切れ、ネットワークエラー)自体もsecurity_alert_delivery_failedとしてログに記録されるため、静かに壊れた Webhook が「試行なし」と読まれることはありません。
Webhook の POST は Next の after() を使用してスケジュールされ、レスポンスが送信された後に実行されます(認証チェックに追加のレイテンシは発生しません)。これは実際のリクエスト内でのみ機能するため、直接呼び出された場合(テストなど)は単純な fire-and-forget 呼び出しにフォールバックします。
これは意図的に「すべての失敗でアラート」というシンプルな設計であり、しきい値/レートベースのアラートではありません。スコープ外としたもの(カウントベースのしきい値、Vercel のプラットフォームレベルの監視、クレデンシャルのローテーション)とその理由については、lib/auth.ts/lib/securityAlert.ts の doc コメントを参照してください。
公開ツール
ツール | タイプ | 必要な認証 | 説明 |
| 読み取り | OAuth2(アプリ) | 名前で FatSecret の食品データベースを検索 |
| 読み取り | OAuth2(アプリ) | 1 つの食品の完全な 1 食あたりの栄養情報 |
| 読み取り | OAuth2(アプリ) | FatSecret のレシピデータベースを検索 |
| 読み取り | OAuth2(アプリ) | 1 つのレシピの完全な材料/手順 |
| 読み取り | OAuth2(アプリ) | GTIN-13 バーコードを foodId に解決 — |
| 読み取り | OAuth1(ユーザー) | 指定日のフードダイアリーエントリを一覧表示 |
| 読み取り | OAuth1(ユーザー) | お気に入りの食品を一覧表示 |
| 読み取り | OAuth1(ユーザー) | よく食べる食品を一覧表示(食事別も可能) |
| 読み取り | OAuth1(ユーザー) | 最近食べた食品を一覧表示(食事別も可能) |
| 読み取り | OAuth1(ユーザー) | 指定月の体重エントリを一覧表示 — Premier 限定の可能性あり |
| 読み取り | OAuth1(ユーザー) | 指定日のエクササイズエントリを一覧表示 |
| 読み取り | OAuth1(ユーザー) | ユーザーの FatSecret プロフィール概要を取得 |
| 書き込み | OAuth1(ユーザー) | 食品をダイアリーに記録 |
| 書き込み | OAuth1(ユーザー) | 既存のダイアリーエントリを更新 |
| 書き込み | OAuth1(ユーザー) | ダイアリーエントリを削除 |
| 書き込み | OAuth1(ユーザー) | 体重エントリを記録/更新 — Premier 限定の可能性あり |
| 書き込み | OAuth1(ユーザー) | エクササイズエントリを記録 |
書き込みツールはデフォルトでドライラン
fitness-mcp と同じ設計です。すべての書き込みツールは confirm: true 引数を必要とします。その説明は、呼び出し側の LLM に、書き込まれる内容をユーザーに正確に表示し、事前に明示的な承認を得るように指示します。これは構造的な後押しであり、保証ではありません。ツールを呼び出すかどうかを決定する同じ LLM が confirm も設定し、認証レイヤーで読み取り/書き込みツールのスコープ分離がないため、有効な MCP_BEARER_TOKEN を保持する呼び出し元は任意のツールを呼び出すことができます。
未検証のもの
このプロジェクトが最初に構築されたとき、FatSecret API の登録は存在しなかったため、ほとんどはベストエフォートの再構築として始まりました。その後、一部のツールは実際のアカウントでチェックされています。ステータスは以下のとおりです。
実稼働確認済み、実装と完全に一致:
search_foods(foods.search)、get_food_diary(food_entries.get、mealフィールドの実際の大文字小文字も含む。例:"Breakfast")。実稼働確認済み、確認後に修正:
get_profile(profile.get) — 実際のレスポンスにheight_cmが含まれていたが、まだフィールドとして公開されていなかったため、追加した。実稼働確認済み、実際の形状は想定より複雑:
get_exercise_diary(exercise_entries.get)。メソッド/エンベロープは実在するが、連携したヘルスアプリから同期された実際のエントリ ({exercise_id: "184", exercise_name: "Google Health Connect", minutes: "1440", calories: "1655"}— 単一のワークアウトではなく、1日分の集計アクティビティ) にはexercise_entry_idもdate_intもまったくない。lib/fatsecret/exercise.tsは現在これを防御的に処理している (欠落フィールドはクラッシュや誤解を招く捏造値ではなくnullになる) ほか、完全な生エントリをrawの下に保持する。依然未解決: (FatSecret アプリ経由で) 手動で記録されたエクササイズに、food_entries.getのエントリのように id/date があるかどうか — 未テスト。依然未検証 / ベストエフォートでの再構築:
food.find_id_for_barcodeのレスポンス形状、weight.updateのパラメータ名、create_exercise_entryのメソッド名とパラメータ (上記のエクササイズ日記の発見により、「個別に作成可能なエントリ」というデータモデルの前提全体が成立しない可能性がある —lib/fatsecret/exercise.tsの警告を参照)。これらは出発点として扱い、検証済みの事実とは見なさないこと。上記2つの箇条書きについては、実際のアカウントに対して以下の手動検証チェックリストを実行し、見つかった不一致を修正すること (
lib/fatsecret/*.test.tsのユニットテストもそれに合わせて更新が必要)。
セットアップ
FatSecret Platform API アプリを登録する: https://platform.fatsecret.com/。以下が取得できる:
OAuth 2.0 クライアント ID/シークレット (
FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET用)。OAuth 1.0 コンシューマーキー/シークレット (
FATSECRET_CONSUMER_KEY/FATSECRET_CONSUMER_SECRET用) — 同じアプリからの別のペアであり、上記の OAuth2 認証情報とは異なる。プランに含まれるスコープを確認する (
basic/premier/barcode/ ...) —weights.get_month/weight.update/find_food_by_barcodeは Premier またはbarcode/premierスコープが必要と報告されている。自分のプランで確認し、必要に応じてFATSECRET_OAUTH2_SCOPEを調整すること。送信 IP を許可リストに登録する (最大15アドレス/レンジ) — FatSecret の IP 制限はトークンエンドポイントに限定されない: 実際の Vercel デプロイで、実際の
foods.searchAPI 呼び出し自体が許可リスト外の IP から拒否されることを確認済み (エラーコード 21、「Invalid IP address detected」)。トークンが正しく発行されていても同様。したがって、一度きりの OAuth2 トークン取得と、すべての検索/詳細呼び出しの両方が許可リスト登録済み IP から発信される必要がある。ローカルではこれは単に自分のマシンのパブリック IP (curl https://ifconfig.me) である。Vercel では、サーバーレス関数はデフォルトで固定送信 IP を持たないため、下記の「Vercel の固定送信 IP」を参照 — 本番環境で Signed Request ツールが動作する前に必須。
ローカル開発サーバーを一度実行して検索をスモークテストする (フェーズ2はステップ1のみ必要):
npm install cp .env.example .env.local # fill in FATSECRET_CLIENT_ID/SECRET + the MCP_BEARER_TOKEN/OAuth trio vercel dev一度きりの 3-legged OAuth1 セットアップを実行する (5つの検索/詳細ツール以外のすべてのツールに必要) — 下記のフェーズ3を参照。
Vercel にデプロイする — 下記の「デプロイ」を参照。ただし、先に「Vercel の固定送信 IP」を読むこと。
Vercel の固定送信 IP
Vercel のサーバーレス関数には固定送信 IP がない。これは上記の発見を踏まえると問題である — トークン取得だけでなく、search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode のすべての呼び出しが許可リスト登録済み IP から発信される必要がある。これがないと、これら5つのツールはローカルでは正常に動作するが (許可リスト登録したのは自分のマシンの IP なので)、本番環境では FatSecret API error 21: Invalid IP address detected で失敗する。
修正方法: これらのリクエストを固定 IP の HTTP プロキシ経由でルーティングする。このサーバーは Fixie を標準でサポートしている:
usefixie.com でサインアップする — 無料の
tricycleFreeプラン (月500リクエスト/100MB、$0) で個人利用には十分。これは FatSecret の Signed Request トラフィックのみを運び、アプリ全体ではないため。プランのリクエスト枠は、アプリのみのレート制限とは異なり実際の制約であることに注意 — よく検索する場合は使用量を監視し、近づいたらアップグレードする (commuter、$5/月/2,500リクエスト)。Fixie が提供するプロキシ URL をコピーする (
http://fixie:<password>@<host>:<port>)。それを
FIXIE_URLとして設定する — プロキシ経由のローカルテストでは.env.localに、本番用には Vercel の環境変数として。通常のローカル開発では未設定のままにする (自分の IP がすでに直接許可リスト登録されているため) —lib/fatsecret/appAuth.tsはFIXIE_URLが存在する場合にのみプロキシ経由でルーティングする。Fixie の固定 IP (Fixie ダッシュボードに表示される) を FatSecret 開発者コンソールで許可リストに登録する。ローカル開発用に許可リスト登録した IP に加えて (代わりではなく)。
このプロキシを経由する他のサーバーから FatSecret へのトラフィックはない — lib/fatsecret/oauth1.ts の OAuth1 (Signed & Delegated) リクエストは IP 制限されていないため、日記/体重/エクササイズ/プロフィールツールには FIXIE_URL はまったく不要。
ローカル開発
npm install
cp .env.example .env.local # fill in real values
vercel devスモークテスト ($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"}'上記17ツールが返されるはず。トークンが欠落/誤っているリクエストは 401 になるはず。
フェーズ3: 一度きりの 3-legged OAuth1 セットアップ
search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode 以外のすべてのツールには、あなたの FatSecret アカウントに紐づく OAuth1 アクセストークン/シークレットが必要。一度取得する:
npm run fatsecret:oauth-setupこれ (scripts/fatsecret-oauth-setup.ts) は以下を行う:
FatSecret から未承認のリクエストトークンを要求する。
認可 URL を表示する — 開いて FatSecret にログインし、承認する。FatSecret は確認コードを表示する。
そのコードを貼り付けるよう促し、永続的なアクセストークン/シークレットと交換する。
FATSECRET_ACCESS_TOKEN/FATSECRET_ACCESS_TOKEN_SECRETを.env.localに書き込む。
その後、同じ2つの値を Vercel の環境変数にも追加する (.env.local はデプロイされない) — 下記の「デプロイ」を参照。
FatSecret のドキュメントによると、このアクセストークンは期限切れにならない。もし失効した場合 (例: FatSecret アカウント設定からアプリのアクセスを削除した場合)、スクリプトを再実行して新しいものを取得するだけ — fitness-mcp の derive() パターンの精神に従って考えてほしい: ここで認証情報を失っても災害ではなく、ワンコマンドで修正できる。今回は決定的な再導出ではなく対話式であるだけだ。
覚えやすい1つのパスフレーズから Claude 向けシークレットを生成
MCP_BEARER_TOKEN、OAUTH_CLIENT_ID、OAUTH_CLIENT_SECRET (レイヤー ① — Claude ↔ このサーバー間。上記の FatSecret 認証情報とは無関係) はすべて単一のマスターパスフレーズから決定的に導出できる。保存された値を失っても災害にはならない — 再導出するだけ:
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ラベル文字列は秘密ではない (この README に保持しても安全) — 秘密なのはパスフレーズのみ。同じパスフレーズで derive を再実行すると、常に同じ値が再現される。これは FatSecret 側の認証情報 (FATSECRET_CLIENT_ID/SECRET、FATSECRET_CONSUMER_KEY/SECRET、FATSECRET_ACCESS_TOKEN/SECRET) には適用されない — これらは FatSecret の開発者コンソールと OAuth1 セットアップスクリプトから取得され、このパスフレーズからは取得されない。
テスト
3つのレイヤーがあり、すべて CI (.github/workflows/ci.yml) でプッシュ/PR のたびに実行される — いずれも実際の FatSecret シークレットを必要としないため、公開リポジトリでも同じように動作する:
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)ユニット (
lib/**/*.test.ts): ベアラートークン検証、OAuth2.1 コード署名/PKCE/リダイレクト URI 許可リスト (RFC 7636 テストベクターを含む)、FatSecret OAuth2 Client Credentials トークン取得/キャッシュ/リフレッシュ (lib/fatsecret/appAuth.test.ts)、独立した再実装と相互検証する OAuth1 HMAC-SHA1 署名 (lib/fatsecret/oauth1.test.ts)、およびすべてのlib/fatsecret/*.tsレスポンス形状の正規化 (単一オブジェクト vs 配列、数値文字列 vs 数値、空レスポンスの癖)。統合 (
test/integration/*.test.ts): 実際のapp/api/mcp/route.tsハンドラを実際のlib/fatsecret/*モジュールに接続し、fetchのみモックして、OAuth2 (Signed Request) と OAuth1 (Signed & Delegated) の両方のツールパス、およびすべての書き込みツールの確認ゲーティングをカバー。実際の/api/oauth/authorize//api/oauth/tokenルート。.well-knownOAuth メタデータルート。E2E (
test/e2e/*.e2e.test.mjs): 本番ビルドを起動し、実際の HTTP で検証 — ヘルスチェック、認証欠落/不正時の 401、tools/listが全17ツールを返すこと、OAuth ディスカバリメタデータ、完全な認可コード + PKCE ラウンドトリップ。実際の FatSecret データは使用しない (CI には設計上、実際の認証情報がない)。
実際の FatSecret アカウントでの手動検証
CI は実際の FatSecret データに触れることはなく、上記の「未検証の内容」によると、このサーバーの FatSecret の正確なレスポンス形状に関する前提の一部は実際のアカウントでまったく確認されていない。登録して OAuth1 セットアップスクリプトを実行したら、このチェックリストを実行し、見つかった不一致を修正すること:
.env.localに実際のFATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRETを設定し、vercel devを実行して、実際のクエリでsearch_foodsを呼び出す— 完了、実際のアカウントで動作することを確認済み。まだの場合はget_food_detailでも同様に行うこと — 妥当な栄養数値が返ることを確認する。同様に
search_recipesとget_recipe_detailを呼び出す。依然未解決。プランに
barcodeスコープが含まれる場合、実際の製品のバーコードでfind_food_by_barcodeを呼び出し、レスポンス形状がlib/fatsecret/foods.tsのRawFindIdForBarcodeResponseと一致することを確認する — 一致しなければ修正する。依然未解決。npm run fatsecret:oauth-setupを実行し、get_profileとget_food_diaryを呼び出す— 完了。get_food_diaryは完全に一致。get_profileはheightCmが欠落していたため修正済み — 上記の「未検証の内容」を参照。confirm: trueで明らかに使い捨てのエントリをcreate_food_diary_entryで作成し、同じ日付でget_food_diaryを呼び出して、正しい食品/分量/数量/食事で表示されることを確認する。次にupdate_food_diary_entryで更新し、delete_food_diary_entryで削除する — それぞれがラウンドトリップすることを確認する。依然未解決 —get_food_diaryからmealは大文字で返される ("Breakfast") ことに注意。create_food_diary_entry/update_food_diary_entryが書き込み時に同じ大文字小文字 (または FatSecret の書き込み側が実際に期待する大文字小文字) を受け入れるかどうかを、問題ないと決めつける前に再確認する価値がある。プランに体重追跡が含まれる場合、
confirm: trueでupdate_weightを呼び出し、get_weight_historyがそれを反映することを確認する。依然未解決。create_exercise_entryとget_exercise_diaryはこのコードベースで最も検証が進んでいないペアである。get_exercise_diaryのメソッド/エンベロープは実在することが確認されたが、エクササイズ日記のデータモデルが想定より複雑であることが明らかになった (上記の「未検証の内容」を参照) —create_exercise_entryを信頼する前に、まず FatSecret アプリで手動でエクササイズを記録し、get_exercise_diaryを再確認して、手動エントリに食品エントリのようなexercise_entry_id/date_intがあるかどうかを確認すること。そうすれば、「個別に作成可能なエントリ」がそもそも正しいモデルかどうかがわかる。その後で実際のデータに対してcreate_exercise_entry自体を試すこと。実際の FatSecret 認証情報をコミットしないこと。また、このチェックリストを CI で実行しないこと。
環境変数
変数 | 目的 |
| OAuth 2.0 クライアント認証情報 — 署名付きリクエスト方式(検索・詳細ツール) |
| 任意。スペース区切りの OAuth2 スコープ。デフォルトは |
| 任意。デフォルトは |
| 任意。OAuth2 トークン取得とすべての署名付きリクエスト呼び出しに使用する固定 IP HTTP プロキシ URL( |
| OAuth 1.0 コンシューマキー/シークレット — ワンタイムセットアップスクリプトと、すべての署名付き・委任呼び出しの両方に署名する |
| あなたの FatSecret アカウント用の OAuth 1.0 アクセストークン/シークレット — |
| このサーバーがすべてのリクエストで要求する共有シークレット。また、OAuth フローが発行する access_token でもある |
| このサーバー自身の最小限の OAuth 認可サーバー用の認証情報 |
| 任意。 |
| 任意。認証失敗時のリアルタイムアラート用 Slack/Discord 受信 Webhook URL — 上記「セキュリティイベントのログ記録とアラート」を参照。この設定の有無にかかわらず、失敗は常に |
これらは Vercel プロジェクトの環境変数(Production + Preview)に設定すること。実際の値は絶対にコミットしないこと — .env.example は名前を文書化するだけである。
デプロイ
vercel linkvercel env add FATSECRET_CLIENT_ID(上記の表の変数のうち、値を持つものすべてに対して繰り返す — 最低限FATSECRET_CLIENT_ID/SECRET、MCP_BEARER_TOKEN、OAUTH_CLIENT_ID/SECRET。上記「Vercel の固定送信 IP」に従ってFIXIE_URLを追加 — 実際には任意ではなく必須。OAuth1 セットアップスクリプトを実行したらFATSECRET_CONSUMER_*/FATSECRET_ACCESS_TOKEN*のペアを追加)デプロイ前に、Vercel プロジェクトの Node.js バージョンを 22.19 以降に設定すること(Project → Settings → General → Node.js Version、または現在の Vercel ダッシュボードで該当する場所)— つまり下記の手順 4 の前。このサーバーの
undici@8依存関係(Fixie プロキシに使用 — 上記「Vercel の固定送信 IP」を参照)は"engines": {"node": ">=22.19.0"}を宣言しており、package.json自身のenginesフィールドも同じ要件を文書化している — しかし、どちらも Vercel 上では単独では何も強制しないため、古い Node バージョン(例: 20.x)に固定されたプロジェクトは「成功」としてデプロイされ、実行時に失敗する。Vercel ダッシュボードでこの GitHub リポジトリを接続し、
mainへのプッシュで自動デプロイするか、手動でvercel --prodを実行する。デプロイされた URL をメモする(Project → Settings → Domains を確認 — このプロジェクトの本番 URL は未取得の
https://fatsecret-mcp.vercel.appであることが判明したが、これは Vercel の共有名前空間なので、フォークでも空いているとは想定しないこと)。FatSecret 開発者コンソールで Fixie の固定 IP を許可リストに追加する(上記「Vercel の固定送信 IP」を参照)— これは本番環境で最も問題になりやすい手順である。これがないと
search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcodeがすべてFatSecret API error 21で失敗するため。
Claude に接続
カスタムコネクタは claude.ai(Web)またはデスクトップアプリからのみ追加できる — モバイルアプリからは不可。追加後はモバイルからも自動的に使用できる。
claude.ai で: Settings → Connectors → Add custom connector。
名前:
FatSecret。URL:https://<your-deployment>/api/mcp。アカウントに「Request headers」ベータがある場合: そこに
Authorization: Bearer <MCP_BEARER_TOKEN>を追加し、手順 5 に進む。それ以外の場合、Advanced settings を開き、Vercel で設定した
OAUTH_CLIENT_ID/OAUTH_CLIENT_SECRETの値を OAuth Client ID / OAuth Client Secret に入力する。Claude はこのサーバーの.well-knownメタデータを介して/authorizeと/tokenエンドポイントを自動的に検出する。保存する。Claude は上記の 17 個のツールを一覧表示するはずだ。
次のように試してみて: 「バナナのカロリーを教えて」、または「今日の朝食にバナナを1本記録して」(フェーズ 3/4 がセットアップされ検証された後)。
謝辞
3-legged OAuth1 フローの設計は fcoury/fatsecret-mcp(MIT)に基づいている。このプロジェクトは OAuth フローを MCP ツール自体として公開しているが、本プロジェクトは単一の個人用 FatSecret アカウント向けに構築されているため、代わりにスタンドアロンのセットアップスクリプト(scripts/fatsecret-oauth-setup.ts)として一度だけ実行する。コードは一切コピーしていない。
This server cannot be deployed
Maintenance
Related MCP Connectors
Unlock the power of food transparency with our Open Food Facts MCP server. Easily look up any food
MCP server exposing supplements database used by iNutriPlan.com
A calorie MCP that looks up calories and macros from a 4M+ food catalog, not model guesses.
- mcpOAuthcom.zomato
An MCP server that exposes functionalities to use Zomato's services.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for managing food diary, nutrition tracking, meal planning, and weight logging via the FatSecret Platform API.15MIT
- AlicenseNot gradedqualityBmaintenanceA remote MCP server for personal nutrition tracking that enables logging meals, tracking macros, and reviewing nutrition history through conversation.38 npm66MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for USDA nutrition data lookup, meal logging, and daily macro tracking.38 npmMIT
- AlicenseNot gradedqualityDmaintenanceA remote MCP server for personal nutrition tracking that lets you log meals, track macros, water, and body weight, and review your nutrition history through conversation.38 npmMIT