foodvisor-mcp

foodvisor-mcp

MCP server integrating Foodvisor nutrition API for food search, meal logging, daily summaries, and progress tracking via LLM agents like Claude.

Category
Visit Server

README

foodvisor-mcp

A remote Model Context Protocol server that exposes the Foodvisor nutrition API to LLM agents (Claude, Cursor, …). Search foods, log meals, fetch progress and macros — all from your assistant.

Disclaimer. This project is unofficial. It uses Foodvisor's private mobile API by reverse-engineering its requests and is not endorsed by Foodvisor. Use at your own risk; endpoints may change without notice.

Features

  • šŸ„— Catalog search with calories, macros, brand, image, Nutriscore.
  • šŸ“’ Log meals (breakfast/lunch/dinner/snack/custom_*) with quantities and serving multipliers.
  • šŸ“Š Daily summary — server-side aggregation of calories and macros vs. your targets.
  • šŸ“ˆ Progress — daily calories, weight and grade history (ā‰ˆ90 days).
  • šŸ”„ Streak — current consecutive logging days and freezes available.
  • šŸ’§ Hydration log.
  • šŸ‘¤ Profile & nutritional goals — per-weekday calorie/macro targets.
  • šŸ” OAuth 2.1 + PKCE with dynamic client registration — works as a one-click Claude connector.
  • šŸ”„ Stateless multi-user: tokens are self-contained (no database). Foodvisor refresh tokens are encrypted (AES-256-GCM) inside the OAuth-issued JWT.
  • ā™»ļø Automatic access-token refresh with in-memory caching and stampede protection.

Available MCP tools

Tool Description
search_food Search the Foodvisor catalog by free-text query.
get_food_details Full nutritional info (macros, vitamins, units) for one or more food_ids.
log_meal Add foods to a meal slot on a given date.
list_meals Logged meals on a date range.
get_daily_summary Total calories/macros for a day vs. your targets.
get_progress Daily calories, weight and Foodvisor grade for ~90 days.
get_fv_grade_distribution Share of A/B/C/D meals over rolling 7/30/90 day windows.
get_streak Current logging streak and freezes.
get_water_log Daily water intake on a date range.
get_profile Profile and nutritional goals.

Quick start with Docker

git clone https://github.com/cldt-fr/foodvisor-mcp.git
cd foodvisor-mcp
docker compose up -d

The server now listens on http://localhost:3000/mcp. Health probe at /health.

To run behind a reverse proxy (Caddy, Traefik, nginx) on a public domain, just terminate TLS in front of port 3000.

Authentication

foodvisor-mcp supports two ways to authenticate, both backed by the same underlying credential — your Foodvisor refresh token:

  1. OAuth 2.1 (recommended) — the server is a full OAuth authorization server with dynamic client registration and PKCE. Compatible MCP clients (Claude, Cursor, …) handle the flow automatically: they discover the auth endpoints, register themselves, and open a login page where you paste your Foodvisor refresh token once. The server then issues its own JWT with your refresh token AES-256-GCM-encrypted inside.
  2. Direct Bearer (power-user) — pass your Foodvisor refresh JWT directly as Authorization: Bearer …. Useful for scripts or quick tests. The server detects the token shape and proxies as before.

Either way, no per-user state is stored on the server: the OAuth-issued JWT is self-contained and the legacy mode is purely passthrough.

Obtaining your Foodvisor refresh token

Foodvisor only authenticates via Apple Sign-In on iOS — there is no public OAuth or password endpoint. Capture the POST /user/auth/ response on a real iPhone with Charles Proxy (or Proxyman, mitmproxy, …) configured as an HTTPS man-in-the-middle:

  1. Install Charles' root certificate on your iPhone and enable full trust.
  2. Force-quit and reopen the Foodvisor app, then sign in.
  3. Look for a POST https://api.foodvisor.io/api/6.0/ios/FR/fr_FR/user/auth/ request. The JSON response contains tokens.refresh — that's your long-lived credential (ā‰ˆ 6 months).

Refresh tokens give full access to your nutrition history. Treat them like passwords.

Configuring an MCP client

Claude (web / Desktop / Code) — OAuth

Add the server as a connector with its public /mcp URL (e.g. https://foodvisor-mcp.example.com/mcp). Claude will:

  1. Discover the OAuth metadata at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server.
  2. Register itself via POST /register.
  3. Open the /authorize page in your browser. Paste your Foodvisor refresh token in the form and submit.
  4. Exchange the returned code for a long-lived access token (default 30 days).

After that you can use the tools directly from Claude. When the access token expires, Claude re-runs the flow.

Direct Bearer (any MCP client speaking Streamable HTTP)

{
  "mcpServers": {
    "foodvisor": {
      "url": "https://foodvisor-mcp.example.com/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_FOODVISOR_REFRESH_TOKEN>"
      }
    }
  }
}

Local development

Requires Node ≄ 22.

npm install
npm run dev      # tsx watch on $PORT (default 3000)
npm run typecheck
npm run build && npm start

Project layout

src/
ā”œā”€ā”€ index.ts                  # Node http server + per-request MCP transport + OAuth routes
ā”œā”€ā”€ env.ts                    # zod-validated env vars
ā”œā”€ā”€ auth/
│   ā”œā”€ā”€ extract.ts            # Bearer parsing — accepts OAuth JWT and legacy Foodvisor refresh
│   └── token-cache.ts        # Foodvisor access-token cache + refresh
ā”œā”€ā”€ oauth/
│   ā”œā”€ā”€ jwt.ts                # HS256 sign/verify + AES-256-GCM encrypt/decrypt
│   ā”œā”€ā”€ store.ts              # in-memory clients + auth codes (TTL)
│   ā”œā”€ā”€ login.ts              # HTML login page (paste refresh token)
│   ā”œā”€ā”€ handlers.ts           # /register, /authorize, /token handlers
│   └── metadata.ts           # /.well-known/* metadata builders
ā”œā”€ā”€ foodvisor/
│   ā”œā”€ā”€ client.ts             # fetch wrapper with 401 retry
│   ā”œā”€ā”€ endpoints.ts          # typed endpoint helpers
│   └── types.ts              # response shapes
└── mcp/
    ā”œā”€ā”€ server.ts             # createMcpServer(ctx)
    └── tools/                # one file per tool group
        ā”œā”€ā”€ food.ts
        ā”œā”€ā”€ meal.ts
        ā”œā”€ā”€ progress.ts
        ā”œā”€ā”€ trackers.ts
        └── profile.ts

The HTTP server is intentionally minimal (no Express/Hono) — each POST /mcp spins up a fresh McpServer bound to the caller's userId/refreshToken and a stateless StreamableHTTPServerTransport.

Environment variables

Var Default Purpose
PORT 3000 HTTP listen port
LOG_LEVEL info debug | info | warn | error
MCP_PUBLIC_URL derived Public origin (e.g. https://foodvisor-mcp.example.com). Used in OAuth metadata. If unset, derived per-request from Host + X-Forwarded-Proto.
MCP_JWT_SECRET random HMAC secret used to sign OAuth-issued tokens. Min 32 chars. Set explicitly in production — otherwise tokens are invalidated on every restart.
MCP_ACCESS_TOKEN_TTL 2592000 Lifetime of OAuth access tokens, in seconds (default 30 days).
FOODVISOR_BASE_URL https://api.foodvisor.io Override only for testing
FOODVISOR_LOCALE_PATH /api/6.0/ios/FR/fr_FR Locale path prefix used by upstream

Generate a stable secret with:

openssl rand -base64 48

Security notes

  • The server is a trusted proxy to Foodvisor: anyone holding a valid Foodvisor refresh token can use it to read and write that user's nutrition data. Front the /mcp endpoint with HTTPS in production and consider IP allowlists if it is exposed publicly.
  • Tokens are kept in process memory only. They are never persisted to disk.
  • The token cache is keyed by the JWT's user_id, so concurrent requests from the same user share a single access token; concurrent refresh attempts coalesce via an in-flight map.

Roadmap

  • Photo-based meal recognition (Foodvisor's killer feature) once the upload endpoint is reverse-engineered.
  • Activities log, weigh-ins, custom recipes & favorites.
  • Optional persistent token store for resilience across restarts.

Contributing

Issues and PRs welcome at https://github.com/cldt-fr/foodvisor-mcp. Please don't open issues asking for help reverse-engineering Foodvisor endpoints; capture them yourself with Charles/Proxyman and contribute a typed wrapper.

License

MIT — see LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured