fatsecret-mcp
fatsecret-mcp
Un servidor MCP (Model Context Protocol) remoto personal que permite a Claude buscar en la base de datos de alimentos/recetas de FatSecret y leer/escribir tu propio diario de alimentos, peso y registro de ejercicio directamente en la conversación. Desplegado en el nivel gratuito Hobby de Vercel. Proyecto hermano de fitness-mcp (Hevy): un servidor MCP por producto, compartiendo el mismo patrón de autenticación.
Licencia
Related MCP server: Nutrition MCP
Estado
Búsqueda (Fase 2): implementada —
search_foods,get_food_detail,search_recipes,get_recipe_detail,find_food_by_barcode. No se necesita autorización de usuario de FatSecret; solo el Client ID/Secret de OAuth 2.0 de la consola de desarrollador de FatSecret.Diario/peso/ejercicio/perfil (Fase 4): implementada, y parcialmente verificada contra una cuenta real de FatSecret —
get_profile,get_food_diaryyget_exercise_diaryestán ahora confirmados en vivo;create_exercise_entry,weight.updateyfind_food_by_barcodesiguen siendo reconstrucciones no verificadas de mejor esfuerzo (consulta "Qué no está verificado" más abajo para el desglose completo).Script de configuración OAuth1 de 3 patas (Fase 3): implementado (
scripts/fatsecret-oauth-setup.ts), aún no ejecutado contra una cuenta real de FatSecret.
Dos capas de autenticación
Este servidor se sitúa entre Claude y FatSecret, y cada una de esas dos relaciones se autentica de forma completamente distinta: eso es lo principal que hay que entender antes de tocar el código.
Claude <──①── this server (fatsecret-mcp) ──②──> FatSecret API① Claude ↔ este servidor — un secreto compartido único, mismo patrón que fitness-mcp. Claude envía Authorization: Bearer <MCP_BEARER_TOKEN> en cada solicitud; lib/auth.ts lo comprueba. Dado que la opción de cabecera estática de Claude sigue estando restringida por beta, este servidor también ejecuta su propio servidor de autorización OAuth 2.1 mínimo (lib/oauth.ts, /api/oauth/authorize, /api/oauth/token) para que los campos estándar de Client ID/Secret de OAuth de Claude funcionen como respaldo siempre disponible — consulta el README de fitness-mcp para el razonamiento completo, que se aplica sin cambios aquí.
Cada fallo en esta capa — un MCP_BEARER_TOKEN incorrecto o ausente, un client_id de OAuth no reconocido, un client_secret incorrecto, PKCE inválido, un redirect_uri no permitido — se registra y, opcionalmente, se alerta en tiempo real; consulta "Registro y alertas de eventos de seguridad" más abajo.
② este servidor ↔ FatSecret — aquí es donde se vuelve más complejo que fitness-mcp, porque FatSecret mismo usa dos versiones diferentes de OAuth para dos tipos diferentes de métodos de API, y no hay forma de evitarlo: así está diseñada la API de FatSecret, no es una elección hecha aquí:
Categoría de método de FatSecret | Métodos de ejemplo | Cómo autentica este servidor |
Solicitud firmada (sin usuario específico involucrado) |
| OAuth 2.0 Credenciales de cliente — |
Solicitud firmada y delegada (lee/escribe tu cuenta de FatSecret) |
| OAuth 1.0a, de 3 patas, firmado con HMAC-SHA1 — |
Concretamente: search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode funcionan en cuanto has registrado una aplicación de FatSecret y has establecido FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET. Todas las demás herramientas necesitan además FATSECRET_CONSUMER_KEY/FATSECRET_CONSUMER_SECRET (OAuth1 — un par de credenciales diferente de la misma aplicación de FatSecret) y FATSECRET_ACCESS_TOKEN/FATSECRET_ACCESS_TOKEN_SECRET (obtenidos ejecutando el script de configuración una vez).
Registro y alertas de eventos de seguridad
Cada comprobación fallida en la capa ① anterior (Claude ↔ este servidor) se informa a través de lib/securityAlert.ts, activando los siguientes puntos:
lib/auth.ts(verifyBearerToken) — token de portador ausente, token de portador incorrecto,MCP_BEARER_TOKENno configurado./api/oauth/authorize—client_idno reconocido,redirect_urino permitido (el caso de redirección abierta queisAllowedRedirectUriexiste para bloquear),response_typeno soportado, desafío PKCE ausente/no S256,OAUTH_CLIENT_SECRETno configurado./api/oauth/token—client_secretincorrecto, código de autorización inválido/expirado, discrepancia entre código/PKCE/redirect_uri,MCP_BEARER_TOKENno configurado.
Dos capas independientes, por lo que esto se degrada con elegancia:
Siempre registrado. Cada fallo anterior escribe una línea de JSON estructurado (
event,reason,ip,userAgent,path,time) astderrmedianteconsole.error— sin configuración necesaria, y en Vercel esto aparece en los registros de funciones del despliegue tal cual. El valor real del token de portador / secreto de cliente / verificador PKCE nunca se incluye — solo metadatos sobre el intento fallido — ya que un mecanismo de detección que pudiera filtrar el secreto que está vigilando anularía el propósito;lib/securityAlert.test.tsylib/auth.test.tslo verifican directamente.Alerta opcional en tiempo real. Si
SECURITY_ALERT_WEBHOOK_URLestá configurado (una URL de "webhook entrante" de Slack o Discord), el mismo evento también se envía allí como un mensaje de una línea, de modo que un intento de intrusión aparece como una notificación push en lugar de ser visible solo cuando alguien abre el visor de registros de Vercel. Un fallo de entrega del webhook (URL expirada, error de red) se registra a su vez comosecurity_alert_delivery_failed, de modo que un webhook roto silenciosamente no se lea como "sin intentos".
El POST del webhook se programa mediante after() de Next para que se ejecute después de que la respuesta ya se haya enviado (sin latencia añadida en la comprobación de autenticación); esto solo funciona dentro de una solicitud real, por lo que se recurre a una llamada simple de disparar y olvidar cuando se invoca directamente (por ejemplo, desde pruebas).
Este es intencionalmente un diseño simple de "alertar en cada fallo", no alertas basadas en umbrales/tasas — consulta los comentarios de documentación de lib/auth.ts/lib/securityAlert.ts para ver qué se excluyó (umbrales basados en recuento, monitorización a nivel de plataforma de Vercel, rotación de credenciales) y por qué.
Herramientas expuestas
Herramienta | Tipo | Autenticación necesaria | Descripción |
| lectura | OAuth2 (aplicación) | Buscar en la base de datos de alimentos de FatSecret por nombre |
| lectura | OAuth2 (aplicación) | Nutrición completa por ración para un alimento |
| lectura | OAuth2 (aplicación) | Buscar en la base de datos de recetas de FatSecret |
| lectura | OAuth2 (aplicación) | Ingredientes/instrucciones completos para una receta |
| lectura | OAuth2 (aplicación) | Resolver un código de barras GTIN-13 a un foodId — necesita el alcance |
| lectura | OAuth1 (usuario) | Listar entradas del diario de alimentos para una fecha |
| lectura | OAuth1 (usuario) | Listar alimentos favoritos |
| lectura | OAuth1 (usuario) | Listar alimentos más consumidos, opcionalmente por comida |
| lectura | OAuth1 (usuario) | Listar alimentos consumidos recientemente, opcionalmente por comida |
| lectura | OAuth1 (usuario) | Listar entradas de peso para un mes — posiblemente solo Premier |
| lectura | OAuth1 (usuario) | Listar entradas de ejercicio para una fecha |
| lectura | OAuth1 (usuario) | Obtener el resumen del perfil de FatSecret del usuario |
| escritura | OAuth1 (usuario) | Registrar un alimento en el diario |
| escritura | OAuth1 (usuario) | Actualizar una entrada de diario existente |
| escritura | OAuth1 (usuario) | Eliminar una entrada de diario |
| escritura | OAuth1 (usuario) | Registrar/actualizar una entrada de peso — posiblemente solo Premier |
| escritura | OAuth1 (usuario) | Registrar una entrada de ejercicio |
Las herramientas de escritura son de prueba en seco por defecto
Mismo diseño que fitness-mcp: cada herramienta de escritura requiere un argumento confirm: true. Sus descripciones instruyen al LLM que llama a mostrar al usuario exactamente lo que se escribirá y obtener una aprobación explícita primero. Eso es un empujón estructural, no una garantía: el mismo LLM que decide si llamar a la herramienta también establece confirm, y no hay separación de alcance entre herramientas de lectura/escritura en la capa de autenticación, por lo que cualquier llamador que tenga un MCP_BEARER_TOKEN válido puede invocar cualquier herramienta.
Qué no está verificado
No existía ningún registro de API de FatSecret cuando se construyó este proyecto por primera vez, por lo que la mayor parte comenzó como reconstrucciones de mejor esfuerzo. Desde entonces se ha comprobado contra una cuenta real para algunas herramientas — estado a continuación:
Confirmado en vivo, coincide exactamente con la implementación:
search_foods(foods.search),get_food_diary(food_entries.get, incluyendo la capitalización real del campomeal, p. ej."Breakfast").Confirmado en vivo, corregido tras la comprobación:
get_profile(profile.get) — una respuesta real incluíaheight_cm, que aún no estaba expuesto como campo; ahora añadido.Confirmado en vivo, la forma real es más compleja de lo asumido:
get_exercise_diary(exercise_entries.get). El método/envoltorio son reales, pero una entrada real sincronizada desde una app de salud conectada ({exercise_id: "184", exercise_name: "Google Health Connect", minutes: "1440", calories: "1655"}— la actividad agregada de un día completo, no un entrenamiento individual) no tieneexercise_entry_idnidate_inten absoluto.lib/fatsecret/exercise.tsahora lo gestiona de forma defensiva (los campos ausentes se convierten ennull, no en un fallo ni en un valor fabricado engañoso) y conserva la entrada bruta completa bajoraw. Sigue abierto: si un ejercicio registrado manualmente (mediante la app de FatSecret) tiene un id/fecha como las entradas defood_entries.get— sin probar.Aún sin verificar / reconstrucciones de buena fe: la forma de la respuesta de
food.find_id_for_barcode, los nombres de parámetros deweight.update, y el nombre del método y los parámetros decreate_exercise_entry(el hallazgo del diario de ejercicio anterior implica que su supuesto modelo de datos de "entrada individual creable" puede no sostenerse — ver la advertencia enlib/fatsecret/exercise.ts). Trátalos como un punto de partida, no como verdad verificada.Ejecuta la lista de verificación de verificación manual que aparece más abajo contra una cuenta real para cualquiera de los dos puntos anteriores, y corrige cualquier discrepancia que encuentres (las pruebas unitarias en
lib/fatsecret/*.test.tsnecesitarán actualizaciones correspondientes).
Configuración
Registra una app de FatSecret Platform API en https://platform.fatsecret.com/. Obtendrás:
Un Client ID/Secret de OAuth 2.0 (para
FATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRET).Un Consumer Key/Secret de OAuth 1.0 (para
FATSECRET_CONSUMER_KEY/FATSECRET_CONSUMER_SECRET) — un par separado de la misma app, no el mismo que las credenciales OAuth2 anteriores.Comprueba qué ámbitos (scopes) incluye tu plan (
basic/premier/barcode/ ...) — se informa queweights.get_month/weight.update/find_food_by_barcoderequieren Premier o los ámbitosbarcode/premier; confírmalo con tu propio plan y ajustaFATSECRET_OAUTH2_SCOPEsi es necesario.Añade a la lista blanca tu(s) IP(s) de salida (hasta 15 direcciones/rangos) — la restricción de IP de FatSecret no se limita al endpoint de token: confirmado contra un despliegue real de Vercel que la propia llamada a la API
foods.searchfue rechazada (código de error 21, "Invalid IP address detected") desde una IP no incluida en la lista blanca, incluso con un token emitido válidamente. Así que tanto la obtención única del token OAuth2 como cada llamada individual de búsqueda/detalle deben originarse desde una IP en la lista blanca. Localmente esto es simplemente la IP pública de tu propia máquina (curl https://ifconfig.me). En Vercel, cuyas funciones serverless no tienen una IP de salida fija por defecto, consulta "Fixed outbound IP for Vercel" más abajo — necesario antes de que cualquier herramienta de Signed Request funcione en producción.
Ejecuta el servidor de desarrollo local una vez para hacer una prueba rápida de búsqueda (la Fase 2 solo necesita el paso 1):
npm install cp .env.example .env.local # fill in FATSECRET_CLIENT_ID/SECRET + the MCP_BEARER_TOKEN/OAuth trio vercel devEjecuta la configuración OAuth1 de tres patas (3-legged) una sola vez (necesaria para todas las herramientas excepto las 5 de búsqueda/detalle) — ver Fase 3 más abajo.
Despliega en Vercel — ver Despliegue más abajo, pero lee primero "Fixed outbound IP for Vercel".
Fixed outbound IP for Vercel
Las funciones serverless de Vercel no tienen una IP de salida fija, lo cual es un problema dado el hallazgo anterior — cada llamada a search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode, no solo la obtención del token, debe provenir de una IP en la lista blanca. Sin esto, esas cinco herramientas funcionan bien localmente (tu IP de máquina es la que añadiste a la lista blanca) pero fallan en producción con FatSecret API error 21: Invalid IP address detected.
Solución: enruta esas peticiones a través de un proxy HTTP con IP fija. Este servidor soporta Fixie de serie:
Regístrate en usefixie.com — el plan gratuito
tricycleFree(500 peticiones/100MB al mes, $0) es suficiente para uso personal, ya que esto solo transporta el tráfico de Signed Request de FatSecret, no toda tu app. Ten en cuenta que la cuota de peticiones del plan es una restricción real, a diferencia de un límite de tasa solo de app — si buscas mucho, vigila el uso y mejora de plan (commuter, $5/mes/2.500 peticiones) si te acercas al límite.Copia la URL del proxy que Fixie te da (
http://fixie:<password>@<host>:<port>).Establécelo como
FIXIE_URL— en.env.localpara pruebas locales contra el proxy, y como variable de entorno de Vercel para producción. Déjalo sin establecer para el desarrollo local ordinario (donde tu propia IP ya está directamente en la lista blanca) —lib/fatsecret/appAuth.tssolo enruta a través del proxy cuandoFIXIE_URLestá presente.Añade la IP fija de Fixie (mostrada en tu panel de Fixie) a la lista blanca en la consola de desarrollador de FatSecret, además de (no en lugar de) cualquier IP que hayas añadido para el desarrollo local.
Ningún otro tráfico servidor-a-FatSecret pasa por este proxy — las peticiones OAuth1 (Signed & Delegated) en lib/fatsecret/oauth1.ts no tienen restricción de IP, así que las herramientas de diario/peso/ejercicio/perfil no necesitan FIXIE_URL en absoluto.
Desarrollo local
npm install
cp .env.example .env.local # fill in real values
vercel devPrueba rápida (sustituye $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"}'Debería devolver las 17 herramientas anteriores. Una petición con un token ausente/incorrecto debería obtener 401.
Fase 3: configuración OAuth1 de tres patas (3-legged) única
Todas las herramientas excepto search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcode necesitan un token/secret de acceso OAuth1 vinculado a tu cuenta de FatSecret. Obténlo una vez:
npm run fatsecret:oauth-setupEsto (scripts/fatsecret-oauth-setup.ts) hará lo siguiente:
Solicitará un token de petición no autorizado a FatSecret.
Imprimirá una URL de autorización — ábrela, inicia sesión en FatSecret y aprueba. FatSecret muestra un código de confirmación.
Te pedirá que pegues ese código, y luego lo intercambiará por un token/secret de acceso permanente.
Escribirá
FATSECRET_ACCESS_TOKEN/FATSECRET_ACCESS_TOKEN_SECRETen.env.local.
Luego añade también esos mismos dos valores a las variables de entorno de Vercel (.env.local nunca se despliega) — ver Despliegue más abajo.
Según la documentación de FatSecret, este token de acceso no caduca. Si alguna vez se revoca (p. ej. eliminas el acceso de la app desde la configuración de tu cuenta de FatSecret), simplemente vuelve a ejecutar el script para obtener uno nuevo — véase el patrón derive() de fitness-mcp en espíritu: perder una credencial aquí no es un desastre, es una corrección de un comando, solo que esta vez interactiva en lugar de una re-derivación determinista.
Generación de los secretos orientados a Claude a partir de una única frase de contraseña memorable
MCP_BEARER_TOKEN, OAUTH_CLIENT_ID y OAUTH_CLIENT_SECRET (capa ① — Claude ↔ este servidor, sin relación con las credenciales de FatSecret anteriores) pueden derivarse todos de forma determinista a partir de una única frase de contraseña maestra, así que perder los valores almacenados no es un desastre — solo hay que re-derivarlos:
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_SECRETLas cadenas de etiqueta no son secretas (es seguro mantenerlas en este README) — solo la frase de contraseña lo es. Ejecutar derive de nuevo con la misma frase de contraseña siempre reproduce los mismos valores. Esto no se aplica a las credenciales del lado de FatSecret (FATSECRET_CLIENT_ID/SECRET, FATSECRET_CONSUMER_KEY/SECRET, FATSECRET_ACCESS_TOKEN/SECRET) — esas provienen de la consola de desarrollador de FatSecret y del script de configuración OAuth1, no de esta frase de contraseña.
Pruebas
Tres capas, todas ejecutadas en CI (.github/workflows/ci.yml) en cada push/PR — ninguna requiere secretos reales de FatSecret, así que funcionan igual en un repositorio público:
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)Unitarias (
lib/**/*.test.ts): verificación del bearer token, firma de código OAuth2.1/PKCE/lista blanca de redirect-URI (vector de prueba RFC 7636 incluido), obtención/caché/refresco de token de Client Credentials OAuth2 de FatSecret (lib/fatsecret/appAuth.test.ts), firma HMAC-SHA1 OAuth1 contrastada con una reimplementación independiente (lib/fatsecret/oauth1.test.ts), y la normalización de la forma de respuesta de cadalib/fatsecret/*.ts(objeto-único-vs-array, cadena-numérica-vs-número, peculiaridades de respuesta vacía).De integración (
test/integration/*.test.ts): el manejador realapp/api/mcp/route.tsconectado a los módulos realeslib/fatsecret/*con solofetchsimulado, cubriendo tanto las rutas de herramientas OAuth2 (Signed Request) como OAuth1 (Signed & Delegated), y el bloqueo por confirmación en cada herramienta de escritura; las rutas reales/api/oauth/authorize//api/oauth/token; las rutas de metadatos OAuth.well-known.E2E (
test/e2e/*.e2e.test.mjs): arranca la compilación de producción y verifica sobre HTTP real — comprobación de salud,401en autenticación incorrecta/ausente,tools/listdevuelve las 17 herramientas, metadatos de descubrimiento OAuth, y un recorrido completo de código de autorización + PKCE. No ejercita datos reales de FatSecret (CI no tiene credenciales reales por diseño).
Verificación manual contra una cuenta real de FatSecret
CI nunca toca datos reales de FatSecret y — según "What's unverified" más arriba — algunas suposiciones de este servidor sobre las formas exactas de respuesta de FatSecret no se han comprobado en absoluto contra una cuenta real. Después de registrarte y ejecutar el script de configuración OAuth1, recorre esta lista de verificación y corrige cualquier discrepancia que encuentres:
EstableceFATSECRET_CLIENT_ID/FATSECRET_CLIENT_SECRETreales en.env.local, ejecutavercel devy llama asearch_foodscon una consulta real— hecho, confirmado que funciona contra una cuenta real. Aún así, haz esto paraget_food_detailsi aún no lo has hecho — confirma que devuelve números de nutrición razonables.Llama a
search_recipesyget_recipe_detailde forma similar. Sigue abierto.Si tu plan incluye el ámbito
barcode, llama afind_food_by_barcodecon el código de barras de un producto real y confirma que la forma de la respuesta coincide conRawFindIdForBarcodeResponsedelib/fatsecret/foods.ts— corrígelo si no es así. Sigue abierto.Ejecutanpm run fatsecret:oauth-setup, y luego llama aget_profiley— hecho.get_food_diaryget_food_diarycoincidió exactamente; aget_profilele faltabaheightCm, ahora corregido — ver "What's unverified" más arriba.Llama a
create_food_diary_entryconconfirm: truey una entrada obviamente desechable, luegoget_food_diarypara la misma fecha y confirma que aparece con la comida/ración/cantidad/comida correctas. Luegoupdate_food_diary_entryydelete_food_diary_entry— confirma que cada una hace el recorrido completo. Sigue abierto — ten en cuenta quemealvuelve capitalizado ("Breakfast") desdeget_food_diary; vale la pena verificar dos veces quecreate_food_diary_entry/update_food_diary_entryaceptan esa misma capitalización al escribir (o la capitalización que el lado de escritura de FatSecret realmente espere) antes de asumir que está bien.Si tu plan incluye el seguimiento de peso, llama a
update_weightconconfirm: truey confirma queget_weight_historylo refleja. Sigue abierto.create_exercise_entryyget_exercise_diaryson el par menos verificado de este código. El método/envoltorio deget_exercise_diaryahora está confirmado como real, pero reveló que el modelo de datos del diario de ejercicio es más complejo de lo asumido (ver "What's unverified" más arriba) — antes de confiar encreate_exercise_entry, registra un ejercicio manualmente en la app de FatSecret primero y vuelve a comprobarget_exercise_diarypara ver si una entrada manual tiene unexercise_entry_id/date_intcomo las entradas de comida; eso te dirá si "entrada individual creable" es siquiera el modelo correcto aquí, antes de probarcreate_exercise_entryen sí contra datos reales.Nunca confirmes credenciales reales de FatSecret, y nunca ejecutes esta lista de verificación en CI.
Variables de entorno
Variable | Propósito |
| Credenciales de cliente OAuth 2.0 — métodos de Signed Request (herramientas de búsqueda/detalle) |
| Opcional. Ámbito(s) OAuth2 separados por espacios, por defecto |
| Opcional. Por defecto |
| Opcional. URL del proxy HTTP de IP fija ( |
| Clave/Secreto de consumidor OAuth 1.0 — firma tanto el script de configuración único como cada llamada Signed y Delegated |
| Token/secreto de acceso OAuth 1.0 para tu cuenta de FatSecret — se obtiene mediante |
| Secreto compartido que este servidor exige en cada petición, y el access_token que emite nuestro flujo OAuth |
| Credenciales para el servidor de autorización OAuth mínimo propio de este servidor |
| Opcional. Lista de permitidos separada por comas para el |
| Opcional. URL de webhook entrante de Slack/Discord para alertas en tiempo real sobre fallos de autenticación — consulta «Security event logging & alerting» más arriba. Los fallos siempre se registran en |
Defínelas en las Variables de Entorno del proyecto de Vercel (Production + Preview). Nunca subas valores reales al repositorio — .env.example solo documenta los nombres.
Despliegue
vercel linkvercel env add FATSECRET_CLIENT_ID(repítelo para cada variable de la tabla anterior de la que tengas un valor — como mínimoFATSECRET_CLIENT_ID/SECRET,MCP_BEARER_TOKEN,OAUTH_CLIENT_ID/SECRET; añadeFIXIE_URLsegún «Fixed outbound IP for Vercel» más arriba — obligatorio, no opcional, en la práctica; añade el parFATSECRET_CONSUMER_*/FATSECRET_ACCESS_TOKEN*una vez que hayas ejecutado el script de configuración OAuth1)Configura la versión de Node.js del proyecto de Vercel a 22.19 o superior (Project → Settings → General → Node.js Version, o donde lo ponga el panel actual de Vercel) antes de desplegar — es decir, antes del paso 4 siguiente. La dependencia
undici@8de este servidor (usada para el proxy Fixie — consulta «Fixed outbound IP for Vercel» más arriba) declara"engines": {"node": ">=22.19.0"}, y el propio campoenginesdepackage.jsondocumenta el mismo requisito — pero ninguno de los dos impone nada por sí solo en Vercel, así que un proyecto fijado a una versión anterior de Node (p. ej. 20.x) se desplegará «correctamente» y luego fallará en tiempo de ejecución.Conecta este repositorio de GitHub en el panel de Vercel para el despliegue automático al hacer push a
main, o ejecutavercel --prodmanualmente.Anota la URL desplegada (consulta Project → Settings → Domains — la URL de producción de este proyecto resultó ser el no reclamado
https://fatsecret-mcp.vercel.app, pero es el espacio de nombres compartido de Vercel, así que no des por hecho que estará libre para un fork).Añade la IP fija de Fixie a la lista de permitidos en la consola de desarrollador de FatSecret (consulta «Fixed outbound IP for Vercel» más arriba) — es el paso que más probablemente cause problemas en producción, ya que sin él
search_foods/get_food_detail/search_recipes/get_recipe_detail/find_food_by_barcodefallan todos conFatSecret API error 21.
Conectar con Claude
Los conectores personalizados solo se pueden añadir desde claude.ai (web) o la aplicación de escritorio — no desde la aplicación móvil. Una vez añadidos allí, se pueden usar desde el móvil automáticamente.
En claude.ai: Settings → Connectors → Add custom connector.
Nombre:
FatSecret. URL:https://<your-deployment>/api/mcp.Si tu cuenta tiene la beta «Request headers»: añade
Authorization: Bearer <MCP_BEARER_TOKEN>allí y salta al paso 5.De lo contrario, abre Advanced settings y rellena OAuth Client ID / OAuth Client Secret con los valores
OAUTH_CLIENT_ID/OAUTH_CLIENT_SECRETdefinidos en Vercel. Claude descubrirá los endpoints/authorizey/tokenautomáticamente mediante los metadatos.well-knownde este servidor.Guarda. Claude debería listar las 17 herramientas anteriores.
Prueba a preguntar: «バナナのカロリーを教えて» (dime las calorías de un plátano), o «今日の朝食にバナナを1本記録して» (registra un plátano para el desayuno de hoy — una vez que las Fases 3/4 estén configuradas y verificadas).
Agradecimientos
El diseño del flujo OAuth1 de 3 patas se basó en fcoury/fatsecret-mcp (MIT), que expone el flujo OAuth como herramientas MCP en sí mismas; este proyecto, en cambio, lo ejecuta una sola vez como script de configuración independiente (scripts/fatsecret-oauth-setup.ts), ya que está pensado para una única cuenta personal de FatSecret en lugar de uso multiusuario. No se copió ningún código de él.
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