fatsecret-mcp
fatsecret-mcp
Claude が FatSecret の食品/レシピデータベースを検索し、自分のフードダイアリー、体重、運動ログを会話の中で直接読み書きできるようにする、個人用のリモート MCP (Model Context Protocol) サーバーです。Vercel の無料 Hobby プランにデプロイされています。fitness-mcp (Hevy) の姉妹プロジェクトで、製品ごとに1つの MCP サーバーを用意し、同じ認証パターンを共有しています。
ライセンス
ステータス
検索 (Phase 2): 実装済み —
search_foods,get_food_detail,search_recipes,get_recipe_detail,find_food_by_barcode。FatSecret ユーザー認証は不要で、FatSecret のデベロッパーコンソールの OAuth 2.0 Client ID/Secret のみが必要です。ダイアリー/体重/運動/プロフィール (Phase 4): 実装済みですが、実際の FatSecret アカウントでは未検証です — この開発中には FatSecret API の登録が存在しなかったためです (下記の「未検証の内容」を参照)。各メソッドの正確なフィールド名を、実際のアカウントで確認してから使用し、不整合があればコード/テストを更新してください。
3-legged OAuth1 セットアップスクリプト (Phase 3): 実装済み (
scripts/fatsecret-oauth-setup.ts)。実際の FatSecret アカウントに対してはまだ実行していません。
2つの認証レイヤー
このサーバーは Claude と FatSecret の間に位置し、その2つの関係はそれぞれまったく異なる方法で認証されます — コードに触れる前に理解しておくべき主な点です。
Claude <──①── this server (fatsecret-mcp) ──②──> FatSecret API① Claude ↔ このサーバー — 共有シークレット1つで、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 を参照してください。ここにもそのまま当てはまります。
② このサーバー ↔ FatSecret — ここが fitness-mcp より複雑な点です。FatSecret 自体が 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 (セットアップスクリプトを一度実行して取得) が必要です。
公開ツール
ツール | 種別 | 必要な認証 | 説明 |
| 読み取り | OAuth2 (app) | FatSecret の食品データベースを名前で検索 |
| 読み取り | OAuth2 (app) | 1つの食品の1食あたりの完全な栄養情報 |
| 読み取り | OAuth2 (app) | FatSecret のレシピデータベースを検索 |
| 読み取り | OAuth2 (app) | 1つのレシピの完全な材料/作り方 |
| 読み取り | OAuth2 (app) | GTIN-13 バーコードを foodId に解決 — |
| 読み取り | OAuth1 (user) | 指定日のフードダイアリーエントリを一覧表示 |
| 読み取り | OAuth1 (user) | お気に入りの食品を一覧表示 |
| 読み取り | OAuth1 (user) | よく食べられている食品を一覧表示 (食事単位で指定可能) |
| 読み取り | OAuth1 (user) | 最近食べた食品を一覧表示 (食事単位で指定可能) |
| 読み取り | OAuth1 (user) | 1か月分の体重エントリを一覧表示 — おそらく Premier 限定 |
| 読み取り | OAuth1 (user) | 指定日の運動エントリを一覧表示 |
| 読み取り | OAuth1 (user) | ユーザーの FatSecret プロフィール概要を取得 |
| 書き込み | OAuth1 (user) | 食品をダイアリーに記録 |
| 書き込み | OAuth1 (user) | 既存のダイアリーエントリを更新 |
| 書き込み | OAuth1 (user) | ダイアリーエントリを削除 |
| 書き込み | OAuth1 (user) | 体重エントリを記録/更新 — おそらく Premier 限定 |
| 書き込み | OAuth1 (user) | 運動エントリを記録 |
書き込みツールはデフォルトでドライラン
fitness-mcp と同じ設計です: すべての書き込みツールは confirm: true 引数を必要とします。ツールの説明には、呼び出し側の LLM に対し、書き込まれる内容を正確にユーザーに表示し、最初に明示的な承認を得るよう指示しています。これは構造的な注意喚起であって保証ではありません — ツールを呼び出すかどうかを決定するのと同じ LLM が confirm も設定するため、また認証レイヤーに読み取り/書き込みツールのスコープ分離がないため、有効な MCP_BEARER_TOKEN を持つ呼び出し元はどのツールでも呼び出せます。
未検証の内容
このプロジェクトの開発中には FatSecret API の登録が存在しませんでした (その手順には人間の操作が必要です — 下記のセットアップを参照)。そのため:
search_foods/get_food_detail/search_recipes/get_recipe_detail/profile.get/food_entries.get/weights.get_monthのメソッド名と主要パラメータは、動作中のサードパーティ製 FatSecret クライアント実装と照合して確認されています (推測ではありません) — 出典は git 履歴を参照してください。food.find_id_for_barcodeのレスポンス構造、weight.updateのパラメータ名、およびexercise_entries.*のすべては、ベストエフォートでの再構成であり、その理由とともにlib/fatsecret/*.ts内にインラインで明記されています。これらは検証済みの事実ではなく、強力な出発点として扱ってください。登録後、実際のアカウントで下記の手動検証チェックリストを実行し、見つかったフィールド名の不一致を修正してください (
lib/fatsecret/*.test.tsのユニットテストも合わせて更新が必要です)。
セットアップ
FatSecret Platform API アプリを登録してください (https://platform.fatsecret.com/)。次のものが取得できます:
OAuth 2.0 Client ID/Secret (
FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET用)。OAuth 1.0 Consumer Key/Secret (
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を調整してください。OAuth2 トークンリクエスト用に送信元 IP を許可リストに追加してください — FatSecret はこれを必須としています (最大15のアドレス/レンジ)。Vercel にデプロイする場合、静的送信元 IP (例: Vercel 対応の egress プロキシ/アドオン) が必要です。Vercel のデフォルトのサーバーレス関数には固定 IP がありません。
ローカル開発サーバーを一度実行して検索のスモークテストをします (Phase 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つのツール以外のすべてに必要) — 下記の Phase 3 を参照。
Vercel にデプロイします — 下記の Deploy を参照。
ローカル開発
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 になるはずです。
Phase 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 はデプロイされません) — 下記の Deploy を参照。
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層あり、すべてのプッシュ/PRでCI(.github/workflows/ci.yml)で実行されます。実際の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クライアント資格情報トークンの取得/キャッシュ/更新(lib/fatsecret/appAuth.test.ts)、独立した再実装と相互検証したOAuth1 HMAC-SHA1署名(lib/fatsecret/oauth1.test.ts)、およびすべてのlib/fatsecret/*.tsレスポンス形状の正規化(単一オブジェクトと配列、数値文字列と数値、空レスポンスの特殊性)。統合テスト(
test/integration/*.test.ts): 実際のapp/api/mcp/route.tsハンドラーを実際のlib/fatsecret/*モジュールに接続し、fetchのみモック化。OAuth2(署名付きリクエスト)とOAuth1(署名・委任)の両方のツールパス、およびすべての書き込みツールの確認ゲートをカバー。実際の/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セットアップスクリプトを実行したら、次のチェックリストを実施し、見つけた不一致を修正してください:
実際の
FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRETを.env.localに設定し、vercel devを実行して、実際のクエリでsearch_foodsを呼び出します(例: 上記のスモークテストのcurlパターンでtools/callを使用)。実際の結果が返り、そのうちの1つで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を呼び出します。lib/fatsecret/profile.ts/lib/fatsecret/diary.tsのフィールド名が実際のレスポンスと一致することを確認します(これらはドキュメントから再構築したもので、キャプチャしたものではありません)。confirm: trueと明らかに使い捨てのエントリでcreate_food_diary_entryを呼び出し、同じ日付のget_food_diaryで、食品/分量/量/食事が正しく表示されることを確認します。その後、update_food_diary_entryで更新し、delete_food_diary_entryで削除します — それぞれが往復することを確認します。プランに体重追跡が含まれる場合は、
confirm: trueでupdate_weightを呼び出し、get_weight_historyに反映されることを確認します。create_exercise_entryとget_exercise_diaryは、このコードベースで最も検証が進んでいないペアです(lib/fatsecret/exercise.tsの冒頭の警告を参照)。これに依存する前に、https://platform.fatsecret.com/docs/guidesで正確なメソッド名/パラメータを確認してください。検証だけでなく、実際の修正が必要になる可能性があります。実際のFatSecret認証情報をコミットせず、このチェックリストをCIで実行しないでください。
環境変数
変数 | 目的 |
| OAuth 2.0 クライアント資格情報 — 署名付きリクエストメソッド(検索/詳細ツール) |
| 任意。スペース区切りのOAuth2スコープ。デフォルトは |
| 任意。デフォルトは |
| OAuth 1.0 コンシューマーキー/シークレット — 一度きりのセットアップスクリプトとすべての署名付き・委任呼び出しの両方に署名します |
| OAuth 1.0 アクセストークン/シークレット(あなたのFatSecretアカウント用) — |
| このサーバーがすべてのリクエストで要求する共有シークレット、およびOAuthフローが発行するaccess_token |
| このサーバー自身の最小限のOAuth認可サーバー用の認証情報 |
| 任意。 |
これらはVercelプロジェクトの環境変数(本番+プレビュー)に設定します。実際の値をコミットしないでください — .env.exampleは名前を文書化しているだけです。
デプロイ
vercel linkvercel env add FATSECRET_CLIENT_ID(上記の表の変数のうち値を持つものすべてについて繰り返します — 最低限FATSECRET_CLIENT_ID/SECRET、MCP_BEARER_TOKEN、OAUTH_CLIENT_ID/SECRET。OAuth1セットアップスクリプトを実行したら、FATSECRET_CONSUMER_*/FATSECRET_ACCESS_TOKEN*のペアも追加します)VercelダッシュボードでこのGitHubリポジトリを接続して
mainへのプッシュで自動デプロイするか、手動でvercel --prodを実行します。デプロイしたURLを確認します(Vercelの共有名前空間では
fatsecret-mcp.vercel.appがすでに使用されている可能性があるため、プロジェクト → 設定 → ドメインを確認してください)。OAuth2トークンリクエストのために、FatSecret開発者コンソールでそのデプロイの送信元IPを許可リストに登録します(セットアップ手順1を参照)— Vercelのサーバーレス関数はデフォルトでは固定IPを持たないため、本番環境で最も問題になりやすい手順です。
Claudeに接続する
カスタムコネクタは、claude.ai(Web)またはデスクトップアプリから追加することしかできません — モバイルアプリからはできません。そこで追加すると、モバイルから自動的に使用できます。
claude.aiで: 設定 → コネクタ → カスタムコネクタを追加。
名前:
FatSecret。URL:https://<your-deployment>/api/mcp。アカウントに「Request headers」ベータ版がある場合: そこに
Authorization: Bearer <MCP_BEARER_TOKEN>を追加し、手順5に進みます。それ以外の場合は、詳細設定を開き、OAuth Client ID / OAuth Client Secretに、Vercelで設定した
OAUTH_CLIENT_ID/OAUTH_CLIENT_SECRETの値を入力します。Claudeは、このサーバーの.well-knownメタデータを介して/authorizeおよび/tokenエンドポイントを自動的に検出します。保存します。Claudeに上記の17のツールが表示されるはずです。
次のように試してください: 「バナナのカロリーを教えて」(バナナのカロリーを教えてください)、または「今日の朝食にバナナを1本記録して」(今日の朝食にバナナを1本記録する — Phase 3/4がセットアップされ、検証されたら)。
謝辞
3-legged OAuth1フローの設計は、fcoury/fatsecret-mcp(MIT)に基づいています。これはOAuthフロー自体をMCPツールとして公開するものです。このプロジェクトは、マルチユーザー利用ではなく単一の個人用FatSecretアカウント向けに構築されているため、代わりにスタンドアロンのセットアップスクリプト(scripts/fatsecret-oauth-setup.ts)として一度だけ実行します。ここからコードはコピーされていません。
This server cannot be installed
Maintenance
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
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
MCP server for Withings health data — sleep, activity, heart, and body metrics.
GibsonAI MCP server: manage your databases with natural language
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ikeike443/fatsecret-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server