Fitatu
Servidor MCP no oficial para Fitatu, el contador de calorías polaco: lee y registra alimentos, peso, agua y entrenamientos, consulta las calorías y macros restantes, y obtén informes semanales. 40 herramientas (23 de solo lectura), modos de solo lectura y demo, cuentas gratuitas y Premium. Python, en PyPI: uvx --from "fitatu-api[mcp]" fitatu-mcp
Documentación
fitatu-api
Un cliente Python no oficial para la API de Fitatu, el contador de
calorías, diseñado para ser utilizado por agentes de IA y scripts. Lee y escribe el diario de
alimentos, actividades, mediciones corporales y agua, lee y establece objetivos, y lee resúmenes y el
catálogo de alimentos.
FitatuTools convierte el diario en herramientas que un modelo de lenguaje puede llamar. El manejo de sesión
sigue a python-garminconnect: inicia sesión una vez,
mantén un archivo de sesión, deja que el cliente lo actualice.
No oficial. Este proyecto no está afiliado ni respaldado por Fitatu Sp. z o.o. La API fue ingeniada inversamente a partir de las aplicaciones de Fitatu y puede cambiar sin previo aviso. El acceso automatizado puede violar los Términos de Servicio de Fitatu; revísalos y usa la biblioteca solo con tu propia cuenta y bajo tu propio riesgo. La licencia MIT cubre este código, no el servicio de Fitatu, su API ni sus datos.
Instalación
Python 3.11 o superior; la única dependencia es requests (y tzdata en Windows).
pip install fitatu-api # the library and the fitatu-api command
pip install "fitatu-api[mcp]" # plus fitatu-mcp, the MCP server
pip install "git+https://github.com/Jezue/fitatu_library" # unreleased changes from main
Para trabajar en la biblioteca o ejecutar sus pruebas sin conexión, clónala en su lugar: git clone https://github.com/Jezue/fitatu_library && cd fitatu_library && pip install -e ".[dev]".
Inicio rápido
fitatu-api login # asks for e-mail and password, writes ~/.fitatu/session.json
¿Te registraste con Apple o Facebook? Entonces la cuenta no tiene contraseña: copia la sesión desde la
aplicación web con fitatu-api import-session en su lugar, como se describe en
Autenticación y archivo de sesión.
from datetime import date
from fitatu_api import FitatuApiClient
with FitatuApiClient.from_session() as client: # closes the HTTP connections at the end
user_id = client.auth.fitatu_user_id
today = date.today()
day = client.planner.get_day(user_id, today)
for meal_key, meal in day["dietPlan"].items():
for row in meal["items"]:
print(meal_key, row["name"], row["energy"], row["planDayDietItemId"])
egg = client.search_food("jajko kurze", limit=1)[0] # search rows carry the id as foodId
added = client.planner.add_product_to_day_meal(
user_id, today, meal_type="breakfast", product_id=egg["foodId"],
measure_id=egg["measure"]["measureId"], measure_quantity=2, # 2 of the hit's measure
)
print("added row", added["row_id"])
Cómo funcionan las escrituras, los IDs de fila y las eliminaciones: docs/PLANNER.md.
Para copiar el menú de una dieta de catering al diario (seguro de ejecutar de nuevo), usa catering_sync.py desde
el repositorio: Importar un menú de catering.
Para agentes de IA
FitatuTools expone 47 herramientas (leer el día, buscar alimentos, registrar alimentos, peso, agua,
entrenamientos, recetas y productos privados, ...) con entradas de JSON Schema y anotaciones de solo lectura / destructivas / idempotentes.
call() nunca lanza excepciones: devuelve {"ok": true, "data": ...} o {"ok": false, "error": {"error_type", "message", "retryable", "hint", ...}}, para que el modelo pueda leer qué salió mal.
SYSTEM_PROMPT es el prompt de sistema recomendado: las reglas que el modelo necesita además de las descripciones
de las herramientas (leer antes de escribir, nombres de comidas propios del usuario, data.ok, confirmaciones). El modelo
pregunta a get_today por la fecha, en la zona horaria de la cuenta.
import json
import anthropic
from fitatu_api import FitatuTools
from fitatu_api.agent import READ_ONLY_TOOLS, SYSTEM_PROMPT, anthropic_tools # openai_tools() for OpenAI
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "How many kcal did I eat today?"}]
# Only the read tools, as this loop runs tool calls without asking the user: call() refuses
# any other tool, which the model can still name.
with FitatuTools.from_session(tools=READ_ONLY_TOOLS) as tools:
while True:
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=16000,
system=SYSTEM_PROMPT,
tools=anthropic_tools(READ_ONLY_TOOLS),
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
break
results = [
{
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(tools.call(block.name, block.input)),
}
for block in response.content
if block.type == "tool_use"
]
messages.append({"role": "user", "content": results})
if response.stop_reason != "end_turn": # max_tokens or refusal: the answer is cut or missing
raise RuntimeError(f"the model stopped early: {response.stop_reason}")
print("".join(block.text for block in response.content if block.type == "text"))
Las herramientas de escritura (registrar alimentos, actualizar, mover, copiar y eliminar filas, peso, agua, entrenamientos, recetas privadas
y productos) necesitan un bucle
que pregunte al usuario antes de llamadas destructivas; está en
docs/AGENTS.md, con la
tabla de herramientas, las llamadas que nunca deben exponerse (tokens de sesión, escrituras en el catálogo), cómo hacer que las escrituras sean seguras
de repetir, qué hacer por error_type, la variante de OpenAI, hosts de larga duración y cómo probar
las herramientas sin una cuenta contra el backend de pruebas sin conexión.
MCP
fitatu-mcp sirve las mismas herramientas a Claude Code, Claude Desktop y otros hosts MCP a través de
stdio, con SYSTEM_PROMPT como sus instrucciones y tres comandos de barra en polaco
(podsumowanie_dnia, przeglad_tygodnia, zaloguj_posilek):
pipx install "fitatu-api[mcp]"
fitatu-api login
claude mcp add fitatu --scope user -- fitatu-mcp # fitatu-mcp --read-only: the read tools only
fitatu-mcp --http sirve las mismas herramientas a través de HTTP, con un token, para n8n, otra computadora o
Docker (el repositorio tiene un Dockerfile):
docs/AGENTS.md.
Sin una cuenta, fitatu-mcp --demo (o FitatuTools.demo()) sirve un pequeño diario ficticio
mantenido en memoria. Para Claude Desktop, cada lanzamiento de GitHub
tiene fitatu-<version>.mcpb, instalado con un doble clic (inicia sesión con fitatu-api login primero). Sin instalar nada, uvx --from "fitatu-api[mcp]" fitatu-mcp ejecuta el servidor. Está
listado en el Registro MCP como
io.github.Jezue/fitatu-api (server.json). Para Hermes Agent y otros hosts que leen
Agent Skills, skills/fitatu-diary/SKILL.md
le dice al agente cómo configurar el servidor y usar bien sus herramientas.
El prompt de permiso del host es el paso de confirmación, así que mantenlo activado para las herramientas destructivas. Claude Desktop, uvx y lo que hace el servidor: docs/AGENTS.md.
Qué cubre
| Área | Cliente (FitatuApiClient) | Herramientas de agente |
|---|---|---|
| Diario de alimentos | client.planner: leer un día, agregar productos, recetas, filas personalizadas y resultados de búsqueda, actualizar, mover, copiar, eliminar; la nota del día | get_day, add_food, add_foods, add_custom_item, update_item, move_item, copy_meal, preview_removal, remove_items, set_note |
| Actividades | planner.add_activity / remove_activity, client.activities (catálogo, búsqueda, recientes) | search_activity, add_activity, remove_activity |
| Alimentos | search_food, get_product_details, get_recipe, catálogo de recetas y su búsqueda, client.foods (favoritos, recientes) | search_food, search_recipes, get_recipe, find_by_barcode, get_food_measures, get_recent_foods, get_favorite_foods, set_favorite |
| Alimentos propios del usuario | search_user_food, create_product, update_product, delete_product, create_recipe, update_recipe, delete_recipe | get_my_foods; create_food, update_food, delete_food y las herramientas de recetas solo para los alimentos privados propios del usuario |
| Mediciones | client.measurements: peso y medidas corporales por día, historial, gráficos | get_weight_history, get_body_measurements, get_measurement_history, log_weight, log_measurements |
| Agua | client.water | get_water, set_water |
| Resumen y exportación | client.summary: totales por rango, nutrientes por día, productos principales, exportación del diario | get_range_summary, get_progress, get_top_foods, get_report, get_shopping_list (calculado a partir de las filas planificadas) |
| Ayuno y hábitos | client.fasting (esquemas, períodos de comida por día), client.habits (catálogo, hábitos del usuario, buenos días); solo lectura | get_fasting, get_habits, get_good_days |
| Objetivos y configuración | client.user_settings: objetivos, BMR/TMR, perfil | get_targets, set_targets (el objetivo manual o automático, división de macronutrientes, tamaño del vaso), get_profile (altura, peso, objetivo, IMC, Premium; nada que identifique al usuario) |
| Escrituras en el catálogo | create_recipe(shared=True), set_product_proposal, limpieza de duplicados | ninguna, a propósito |
FitatuLibrary, que envuelve la mayoría de estos como métodos *_via_api que devuelven {"status": ...}
en lugar de lanzar excepciones, está obsoleto y se eliminará en 1.0: para resultados que nunca lanzan excepciones usa
FitatuTools ({"ok": true, "data": ...}), de lo contrario el cliente. Cada llamada pública con su estabilidad está listada en
docs/API_REFERENCE.md.
Cuentas gratuitas y Premium
| Cuenta gratuita | Premium | |
|---|---|---|
| Diario: leer, registrar, actualizar, mover, copiar, eliminar alimentos, notas, actividades, agua, peso, mediciones corporales | ✅ | ✅ |
Búsqueda, código de barras, medidas de alimentos, búsqueda de recetas por palabras y max_energy_kcal, recetas completas, recetas y productos privados, favoritos, alimentos recientes | ✅ | ✅ |
Filtros de búsqueda de recetas (min_protein_g, max_carbohydrate_g, max_cooking_time, diets, meal) y recetas premium del catálogo (get_recipe, get_food_measures, add_food, add_foods; la lista de compras omite sus ingredientes) | ❌ "necesita Fitatu Premium": las herramientas siguen la aplicación | ✅ |
Objetivos: leer y establecer (get_targets, set_targets), progreso (get_progress), informes (get_report), totales por rango (get_range_summary) | ✅ (progreso: una solicitud por día, como máximo 31 días) | ✅ |
| Historial de peso y mediciones corporales, perfil, ayuno y hábitos (lectura), lista de compras | ✅ | ✅ |
Alimentos principales (get_top_foods, summary.get_top_products()) | ❌ 403: necesita Fitatu Premium | ✅ |
Exportación del diario (fitatu-api export, summary.export_diary()) | ❌ 403: "necesita Fitatu Premium" | ✅ |
Proteína / grasa / carbohidratos día a día (summary.get_nutrient_by_day(); la energía funciona en ambos) | ❌ 403 (get_progress lo lee alrededor) | ✅ |
Casi todo funciona en una cuenta sin Fitatu Premium. Fitatu responde 403 sin él a (verificado en vivo 2026-10-15):
summary.get_nutrient_by_day()para proteína, grasa y carbohidratos (la energía funciona en cualquier cuenta);summary.get_top_products(), y por lo tanto la herramientaget_top_foods;summary.export_diary(), y por lo tantofitatu-api export, que entonces lo dice en una línea.
Fitatu sirve los filtros de búsqueda de recetas y las recetas premium del catálogo a cualquier cuenta, pero su aplicación
los mantiene para Premium, y también las herramientas: verifican los indicadores accessControl de la cuenta y
responden con un error forbidden sin ellos. El cliente en sí no verifica.
get_progress y get_report funcionan en todas las cuentas: cuando se rechaza la ruta día a día de macronutrientes,
leen el resumen de cada día en su lugar (una solicitud por día, como máximo 31 días), y
get_report da top_foods nulo con un top_foods_note. Los objetivos de macronutrientes de una cuenta gratuita son un
rango (target_min por debajo de target_max); en una cuenta Premium un resumen de un día dio los dos
iguales (la ruta día a día get_progress lee allí está de acuerdo, verificado en vivo). También toma un objetivo manual y su propia división de macronutrientes (set_targets, verificado en vivo 2026-10-15); con una división, sus
objetivos de macronutrientes son números únicos. fitatu-api doctor
dice si la cuenta tiene un plan premium. Ver
Cuentas gratuitas y Premium
en docs/AGENTS.md para las herramientas.
Línea de comandos
fitatu-api (también python -m fitatu_api) funciona en el archivo de sesión, $FITATU_SESSION o
~/.fitatu/session.json:
fitatu-api login # or import-session, see Authentication & session file below
fitatu-api status # the session: file, user id, host, token expiry; sends nothing
fitatu-api doctor # checks the session, the clock and the client version with Fitatu
fitatu-api logout # deletes the session file after asking (--yes: without asking)
fitatu-api tools # the agent tools: name, read / write / destructive, what it does
fitatu-api tools --json # the same tools in the Anthropic API format, anthropic_tools()
fitatu-api call get_day '{"date": "2026-10-14"}'
fitatu-api export --from 2026-10-01 --to 2026-10-14 --format csv -o diary.csv # needs Fitatu Premium
status imprime de dónde viene la sesión (el archivo y sus permisos, o
$FITATU_SESSION_JSON), el ID de usuario, el host de la API, las configuraciones regionales, cuándo expira el token de portador y
si hay un token de actualización, sin enviar nada; --check también lee el perfil
una vez. doctor verifica la configuración con Fitatu, una línea ok / WARN / FAIL cada una: los permisos
del archivo de sesión, el token de actualización (actualiza el token de portador una vez y lo guarda, como cualquier
actualización), el reloj de esta computadora contra el tiempo de emisión del token nuevo, una lectura de perfil,
si un plan premium está activo (no hasta cuándo, ni su precio), y si la aplicación web de Fitatu sigue en la versión que la biblioteca envía (GET /upgrade-application/WEB/<version>); sale con 1 cuando una verificación falla y no imprime ningún
token, ID de usuario o directorio de inicio, para que su salida pueda ir a un informe de errores. logout elimina el
archivo de sesión; detén fitatu-mcp y otros procesos que lo usen primero, ya que escribirían
sus tokens actualizados de vuelta. Fitatu no tiene una llamada que la biblioteca conozca que revoque tokens.
Ninguno de estos comandos imprime un token. fitatu-api --version imprime la versión.
call ejecuta una herramienta a través de FitatuTools.call() e imprime su envoltorio como JSON; el estado de
salida es 0 cuando ok es verdadero y 1 cuando es falso. Solo las herramientas de lectura (READ_ONLY_TOOLS)
se ejecutan a menos que se dé --allow-writes. export guarda la exportación del diario de Fitatu (csv, xls, pdf
o txt) en un archivo nuevo legible solo por ti (0600); no reemplaza un archivo existente
sin --overwrite, y un rango sin nada registrado no escribe ningún archivo y sale con 1.
fitatu-api COMMAND --help describe cada comando. Los registros van a stderr, desde WARNING a menos que
fitatu-api --log-level DEBUG COMMAND o FITATU_LOG_LEVEL diga lo contrario (ver
Privacidad y registro).
Autenticación y archivo de sesión
fitatu-api login [--email ADDRESS] [-o PATH] [--base-url URL] (también python -m fitatu_api login) inicia sesión, lee tu perfil para las configuraciones regionales y la zona horaria de la cuenta, y escribe el
archivo de sesión. Lee FITATU_EMAIL y
FITATU_PASSWORD cuando están configurados y solicita de lo contrario. Las cuentas sin contraseña usan
fitatu-api import-session (abajo).
-
Dónde.
fitatu-api login,fitatu-api import-session,FitatuApiClient.from_session(),FitatuTools.from_session()y el obsoletoFitatuLibrary.from_session()usan el mismo archivo: la ruta que pasas (-opara la CLI), si no$FITATU_SESSION, si no$FITATU_SESSION_PATH, si no~/.fitatu/session.json. Un archivo faltante lanzaFitatuAuthErrorindicándote que ejecutesfitatu-api login. -
Qué. JSON con
bearer_token,refresh_token,fitatu_user_id,base_url(el host de la API de la región),app_locale,app_searchlocale,app_storagelocale,app_timezoney una versión de esquema. La identidad del cliente (clave de API, versión de la app, ...) no se almacena; proviene de la biblioteca. -
Permisos. El archivo se escribe solo para el propietario (0600), en un directorio creado con 0700, mediante un archivo temporal que lo reemplaza, de modo que un lector nunca ve media sesión. Contiene tokens en vivo: trátalo como una contraseña.
-
Tokens. Verificados en vivo el 2026-10-13: el token de portador es un JWT que dura una hora. El token de actualización es una cadena opaca que Fitatu no rota:
POST /token/refreshdevuelve un nuevo token de portador y el mismo token de actualización, que sigue funcionando, y los tokens de portador más antiguos siguen siendo válidos hasta que expiren.POST /loginresponde a un correo o contraseña incorrectos con 422, no 401. -
Actualización y reescritura. El cliente actualiza el token de portador 60 segundos antes de que expire (del JWT
exp) y una vez después de un 401, una actualización a la vez. Los tokens se fusionan en el archivo de sesión, de modo que el siguiente proceso comienza con ellos; un proceso que comparte el archivo recoge un par que otro guardó, p. ej. después de quefitatu-api loginse ejecutara de nuevo. Pasapersist_tokens=Falsepara mantener el archivo intacto. Un par de otra cuenta (un inicio de sesión en otra cuenta con el mismo archivo) no se recoge: el cliente en ejecución conserva sus propios tokens y deja de escribir en el archivo, de modo que ese inicio de sesión permanece. Cuando un token recién obtenido de Fitatu ya parece expirado, el reloj de la computadora va rápido: el cliente entonces registra una advertencia y actualiza solo después de un 401. -
Iniciar sesión de nuevo. Cuando Fitatu rechaza el token de actualización, las llamadas lanzan
FitatuAuthError(error_typeauth). Ejecutafitatu-api login(oimport-session) de nuevo; un cliente en ejecución recoge el nuevo par del archivo la próxima vez que necesite una actualización. -
Cuentas sin contraseña. Las cuentas creadas con Apple o Facebook (incluidas las direcciones "Ocultar mi correo" de Apple) no tienen contraseña para
fitatu-api login. Copia la sesión de la aplicación web en su lugar:-
Inicia sesión en https://www.fitatu.com/app/ con Apple o Facebook.
-
Abre la consola de desarrollador del navegador en esa página y ejecuta la línea siguiente. Copia solo los tokens y tu id de usuario; el
localStorage.userde la aplicación web también contiene tu correo, apodo y más.copy(JSON.stringify((u => ({token: u.token, refresh_token: u.refresh_token, id: u.id}))(JSON.parse(localStorage.user)))) -
En macOS ejecuta
pbpaste | fitatu-api import-session. En Linux o Windows pégala en un archivo, ejecutafitatu-api import-session < file(PowerShell:Get-Content file | fitatu-api import-session) y elimina el archivo.
import-session [-o PATH] [--base-url URL]lee el JSON desde stdin (un archivo de sesión de esta biblioteca también funciona), verifica ambos tokens con Fitatu actualizando el portador una vez (así que el guardado es válido durante una hora), lee las configuraciones regionales y la zona horaria de la cuenta comologiny escribe el archivo de sesión de la misma manera. Nada más de la entrada se guarda. El token es una credencial completa de la cuenta: no lo pegues en ningún otro lugar. -
-
Contenedores y cron. Donde no quepa un archivo de sesión escribible, coloca el JSON de sesión en sí en
FITATU_SESSION_JSON:fitatu-api login --print(oimport-session --print) lo imprime en stdout en lugar de escribir un archivo, para un almacén de secretos.from_session()sin una ruta lo toma antes que cualquier archivo y mantiene los tokens que actualiza en memoria: Fitatu no rota el token de actualización, así que el mismo valor funciona para cada ejecución hasta que el token de actualización en sí expire (cuánto dura aún no se sabe) o inicies sesión de nuevo. -
Fachada (obsoleta).
FitatuLibrary.from_session()carga el mismo archivo y escribe los tokens actualizados de vuelta en él.FitatuLibrary(session_data, session_path=...)hace lo mismo para un dict de sesión y copia el par actual ensession_datadespués de cada llamada. -
Desde Python.
FitatuApiClient.login(email, password, token_store_path=path)inicia sesión y fusiona toda la sesión enpath.
Regiones y encabezados
El host de la API es el base_url de la sesión, si no el host de la configuración regional de almacenamiento de la cuenta:
pl_PL se convierte en https://pl-pl.fitatu.com/api, de_DE se convierte en https://de-de.fitatu.com/api.
fitatu-api login inicia sesión en https://pl-pl.fitatu.com/api y almacena el host de la configuración regional de
almacenamiento; con --base-url inicia sesión allí y almacena esa URL.
| Grupo | Encabezados | Notas |
|---|---|---|
| Requeridos | API-Key, API-Secret, Authorization: Bearer <jwt> | La clave y el secreto son valores estáticos de la app (403 sin ellos); Authorization es necesario en rutas de usuario (401). |
| Semánticos | APP-SearchLocale, APP-Locale, APP-StorageLocale, APP-Timezone | APP-SearchLocale y el parámetro de consulta locale cambian los resultados de búsqueda. Los otros describen al usuario. Los cuatro provienen de la sesión, que login() llena desde el perfil; una sesión sin ellos envía los valores predeterminados pl_PL / Europe/Warsaw. |
| Identificación | APP-OS, APP-Version, APP-UUID, API-Cluster, User-Agent | Solo identifican al cliente. La biblioteca siempre envía un perfil constante de la aplicación web (WEB_CLIENT_PROFILE en constants.py), nunca almacenado en sesiones. |
Si Fitatu cambia lo que la aplicación web envía (su versión, o la clave de API y el secreto) antes de que
una versión de la biblioteca lo siga, establece FITATU_CLIENT_PROFILE a un objeto JSON con las claves de
WEB_CLIENT_PROFILE para cambiar, p. ej. FITATU_CLIENT_PROFILE='{"app_version": "4.14.0"}'. Cualquier
otra clave o un valor que no sea texto plano se rechaza con un FitatuValidationError
(fitatu-mcp entonces no se inicia). fitatu-api doctor indica si la versión sigue siendo la
más reciente.
El inicio de sesión (POST /login con _username y _password) y la actualización (POST /token/refresh con
{"refresh_token": ...}) pasan por la misma ruta de solicitud y envían los mismos encabezados, sin
Authorization; en el inicio de sesión, los encabezados de configuración regional siguen siendo los valores predeterminados pl_PL. No hay
firma de solicitudes y Firebase App Check no se aplica; la biblioteca no lo envía.
Las credenciales solo van a hosts https bajo fitatu.com: cualquier otro base_url o URL absoluta
lanza FitatuValidationError antes de que se haga una solicitud, y Authorization solo se envía a
URLs bajo base_url o https://fitatu.com/api. Las redirecciones no se siguen: una respuesta 3xx es
un FitatuApiError, así que un cuerpo de solicitud nunca pasa a otro host.
Errores, reintentos, límites de tasa
Los errores de la biblioteca son subclases de FitatuApiError. describe_error(exc) convierte cualquier
excepción en el dict seguro para JSON que FitatuTools.call() (y el obsoleto FitatuLibrary) devuelven.
| Excepción | Se lanza cuando | error_type |
|---|---|---|
FitatuValidationError (también un ValueError) | Un argumento es inválido; no se envió nada. | validation |
FitatuNotFoundError | El id, la comida o la fila que nombraste no está: la biblioteca lo encontró en lo que leyó (el mensaje lista lo que hay), o el servidor respondió 404 (status_code 404). | not_found |
FitatuAuthError | 401 después de una actualización, un token de actualización rechazado, sin archivo de sesión, o un correo o contraseña incorrectos en el inicio de sesión (Fitatu responde 422); hint entonces apunta a import-session. | auth |
FitatuRateLimitError | 429 después de reintentos; retry_after contiene la espera del servidor en segundos. | rate_limit |
FitatuConnectionError | Sin respuesta HTTP (DNS, tiempo de espera, restablecimiento de conexión). | network |
FitatuMaintenanceError | El encabezado technical-break de Fitatu; display_from / display_to. | maintenance |
FitatuPlannerSyncError | La sincronización del día respondió 202 pero rechazó un día; results tiene los errores por día. | sync_rejected |
FitatuPremiumRequiredError | Una herramienta para lo que la app de Fitatu guarda para Premium, en una cuenta sin ello; no se envió nada para eso. | forbidden |
FitatuApiError | Cualquier otro error HTTP: status_code, body, codename (p. ej. NUMBER_OF_USES_EXCEEDED). | forbidden (403), validation (400/409/422), server |
Los mensajes leen METHOD /path -> status CODENAME: server message. En el mensaje de describe_error()
el id de usuario es <user> (GET /diet-plan/<user>/days -> 403), y con user_id= (que
FitatuTools.call() pasa) donde más aparezca, de modo que un resultado no lo lleva al
proveedor del modelo. Un 403 cuyo cuerpo es una página HTML proviene de un firewall frente a la API (p. ej.
Cloudflare), no de las verificaciones premium o de clave de Fitatu, y su hint lo dice. Cualquier otra excepción, como un TypeError lanzado dentro de la
biblioteca, es unexpected: un error para reportar, ya que FitatuTools.call() verifica los argumentos primero.
Reintentos: los errores de red, 429, 500/502/503/504 y los 520 a 524 de Cloudflare se reintentan durante GET, HEAD y OPTIONS,
y para escrituras marcadas como idempotentes: la sincronización del día (todas las escrituras del planificador; hace upsert por id de fila),
water.set_day, measurements.set_day, measurements.delete_day y foods.set_favorite.
Otras escrituras (escrituras de catálogo, configuraciones, inicio de sesión, actualización) se envían una vez. Hasta
retry_max_attempts=3 intentos con retroceso exponencial desde retry_base_delay_seconds=0.5.
Un Retry-After de hasta 30 segundos se respeta; uno más largo no se espera y el error
se lanza de inmediato (FitatuRateLimitError con retry_after para un 429). Durante una pausa
técnica no se reintenta ni se actualiza nada. Dentro de with client.time_limit(seconds): las solicitudes
terminan dentro de ese tiempo en total: un reintento cuya espera dejaría menos de 2 segundos no se hace, el tiempo de espera de cada
solicitud se reduce al tiempo restante, y una solicitud sin tiempo restante no se envía
(FitatuConnectionError). FitatuTools ejecuta cada llamada en uno de 45 segundos (call_timeout).
La mayoría de las escrituras hacen varias solicitudes, lo que cuenta cuando presupuestas contra 429: las herramientas leen
el día antes de cada escritura de diario, y las actualizaciones, movimientos, eliminaciones y escrituras de actividad lo leen
de nuevo después para establecer ok. Solicitudes por llamada de herramienta del agente, antes de reintentos y actualizaciones de tokens:
| Solicitudes | Herramientas |
|---|---|
| 0 | get_today |
| 1 | las otras herramientas de lectura; set_water; set_favorite; preview_removal y remove_items con dry_run; delete_recipe de una receta ya eliminada, delete_food de un producto ya eliminado |
| 2 | get_range_summary, get_profile, get_fasting (3 cuando la configuración nombra el esquema por id), get_habits, find_by_barcode (1 sin una coincidencia de producto), add_food para una receta en porciones (más 1 para los indicadores Premium, la primera llamada de este tipo en 10 minutos; sin Fitatu Premium, 1 más, ya que lee la receta primero), add_custom_item, log_weight, delete_recipe, set_targets, create_food, delete_food; add_foods, más 1 por cada elemento con unit o measure_id y, sin Fitatu Premium, por cada receta en porciones (y 1 para los indicadores Premium como en add_food); create_recipe, más 1 por cada ingrediente; search_recipes con un filtro pero max_energy_kcal, y get_recipe y get_food_measures de una receta premium, la primera llamada de este tipo en un FitatuTools en 10 minutos (lee los indicadores Premium de la cuenta; 1 después) |
| 3 | add_food con unit o measure_id (lee el alimento primero), log_measurements (lee la unidad de tamaño del perfil), copy_meal dentro de un día, remove_items, add_activity, remove_activity, set_note, update_food; update_recipe, más 1 por cada ingrediente nuevo |
| 4 | update_item, move_item dentro de un día, copy_meal a otro día |
| 5 | get_progress (cualquier rango de hasta 62 días; sin Fitatu Premium, ver más abajo) |
| 6 | move_item a otro día |
| 8 | get_report (uno más por cada 41 pesajes adicionales en el rango) |
| 1 al día | get_shopping_list, más 1 por cada receta planificada en el rango (y 1 para los indicadores Premium cuando una es premium); get_progress y get_report sin Fitatu Premium, más 1 para el rango (ninguno para un solo día) y los pesajes de get_report, y la primera llamada de este tipo en un FitatuTools en 10 minutos, 1 más, que Fitatu rechaza |
Privacidad y registro
La biblioteca registra a través del módulo estándar logging y no configura manejadores. El
comando fitatu-api y fitatu-mcp registran en stderr, nunca en stdout (que lleva el
resultado del comando, o el protocolo MCP): la biblioteca desde WARNING, o desde el nivel que --log-level DEBUG|INFO|WARNING|ERROR (for fitatu-api before the command, e.g. fitatu-api --log-level DEBUG call get_today) or FITATU_LOG_LEVEL establece; otras bibliotecas desde WARNING.
INFO(fitatu_api.client): eventos de autenticación como líneas JSON: inicio de sesión (id de usuario), inicio de refresco de token, éxito y fallo, yclear_auth, con una instantánea de estado no secreta (id de usuario, locales, zona horaria, host, expiración del token, si los tokens están presentes).WARNING(fitatu_api.client):fitatu.request.errorpara una solicitud que falló definitivamente por un error de red, un 429 o un 5xx, después de sus reintentos;fitatu.auth.clock_skew(un token fresco de Fitatu parece expirado, por lo que el reloj local está desajustado; refrescar antes de la expiración se detiene) yfitatu.auth.store_other_account(el archivo de sesión ahora contiene los tokens de otra cuenta; el cliente mantiene los suyos). Desdefitatu_api.agent,fitatu_api.facadeyfitatu_api.mcp_server, una llamada cuyo resultado informa un errorunexpected(con el traceback), un errorautho un errormaintenance:get_day failed (auth): .... Desdefitatu_api.auth, un almacén de tokens (generalmente el archivo de sesión) que no se pudo leer. Desdefitatu_api.mcp_serverbajo--http, cada solicitud rechazada por su token, con la dirección del cliente (nunca el token); uvicorn agrega sus líneas de inicio y detención.DEBUG(fitatu_api.client): cada solicitud como líneas JSON:fitatu.request.start(método, ruta, parámetros de consulta como frases de búsqueda),fitatu.request.retryantes de la espera de cada reintento (elattemptfallido,delay_seconds, y elreason: el estado o el tipo de error de red), luegofitatu.request.okofitatu.request.error(estado,attempt,elapsed_msdesde el inicio, y los primeros 300 caracteres de un cuerpo de error; un 4xx permanece en DEBUG, ya que el llamador lo recibe como una excepción y algunos, como un 404, son esperados). Desdefitatu_api.planner, una línea por escritura del planificador (id de usuario, día, comida, id de alimento, el nombre y kcal de una fila personalizada); desde las capas de herramientas, cualquier otro error que un resultado informe. Las rutas contienen el id de usuario y las fechas.
Los cuerpos de solicitud, contraseñas y tokens nunca se registran: los valores bajo claves que contienen token,
secret, password o authorization se reemplazan con [redacted], y el contexto de autenticación
mantiene los tokens y el secreto de la API fuera de su repr. Los mensajes de error llevan hasta 200 caracteres del
mensaje del servidor; el cuerpo completo de la respuesta está en exc.body, que describe_error() y
los resultados de error de FitatuTools (y el obsoleto FitatuLibrary) omiten. Un token que no es un valor de encabezado válido (por ejemplo, pegado con un
salto de línea) se informa sin citarlo.
Pruebas
pip install -e ".[dev]"
pytest -q
La suite se ejecuta sin conexión. tests/fixtures/api_recording.json contiene respuestas reales de la API (depuradas
de datos personales) para la sincronización diaria, mediciones, resúmenes, búsqueda y configuración;
tests/fake_server.py es un backend falso construido a partir de ellas, y tests/test_recorded_contract.py
falla si el falso se desvía de la grabación. Cómo se hace y se actualiza la grabación:
tests/fixtures/README.md.
La suite en vivo (tests/test_live_all.py) se ejecuta contra una cuenta real y escribe en ella:
FITATU_RUN_LIVE_TESTS=1 pytest tests/test_live_all.py
Usa el archivo de sesión que fitatu-api login escribió (o $FITATU_SESSION) y guarda
los tokens refrescados de nuevo en él; con $FITATU_SESSION_JSON configurado, esa sesión se usa en su lugar y
los tokens refrescados no se guardan. Opcional: FITATU_LIVE_DAY (después de hoy; por defecto un año desde
hoy), FITATU_LIVE_MEAL_KEY (snack), FITATU_LIVE_PRODUCT_ID, FITATU_LIVE_RECIPE_ID,
FITATU_LIVE_MEASUREMENT_DAY (2020-01-01; se omite si tiene una medición) y
FITATU_LIVE_RUN_WRITE_ACCOUNT=1.
Cada prueba elimina exactamente las filas que agregó en FITATU_LIVE_DAY y falla si queda una; un
día en o antes de hoy se rechaza. El agua y la nota de ese día se restablecen, y el peso
y las mediciones escritas en FITATU_LIVE_MEASUREMENT_DAY se eliminan. -k ReadOnly ejecuta solo
las pruebas que leen.
Registrar alimentos del catálogo los agrega a los alimentos recientes de la cuenta, lo que no se deshace. Con
FITATU_LIVE_RUN_WRITE_ACCOUNT=1 la suite también cambia y restaura el tamaño del vaso de agua y los
objetivos diarios (Fitatu mantiene los objetivos restaurados como una nueva versión desde hoy), y crea, luego
elimina, un producto privado y dos recetas privadas (una a través de las herramientas, registrada en
FITATU_LIVE_DAY y eliminada) y un producto privado a través de las herramientas (registrado en
FITATU_LIVE_DAY, cambiado, eliminado). Las eliminaciones de productos y recetas son suaves, por lo que como los alimentos
recientes no se deshacen por completo: permanecen en la cuenta, marcados como eliminados y ocultos de tus
alimentos y búsquedas. La lista completa está en el docstring del módulo de tests/test_live_all.py. Nunca apuntes FITATU_LIVE_DAY a un día con entradas que te importen.
scripts/check_contract.py indica, solo leyendo, si la API en vivo todavía responde con la
estructura que la grabación contiene: imprime nombres de rutas y claves, nunca valores, y sale con 1 cuando una
clave falta, un tipo cambia o una ruta falla. El flujo de trabajo Live contract lo ejecuta y las
pruebas en vivo de solo lectura cada lunes con la sesión de una cuenta desechable en el secreto FITATU_SESSION_JSON,
y se omite sin él:
CONTRIBUTING.md.
scripts/eval_agent.py puntúa qué tan bien un modelo de Claude usa las herramientas en el diario de demostración (29
tareas en polaco e inglés; necesita ANTHROPIC_API_KEY y cuesta uso de API, por lo que CI no lo
ejecuta): docs/AGENTS.md.
Documentación
- docs/AGENTS.md: herramientas, escrituras seguras, manejo de errores y el servidor MCP para agentes.
- docs/PLANNER.md: el contrato de sincronización diaria, ids y el resultado de cada escritura en el diario.
- docs/API_REFERENCE.md: cada clase y método público con su estabilidad.
- docs/APP_4_17_1_API_CATALOG.md: cada ruta de la aplicación Android de Fitatu 4.17.1, desde una descompilación.
- docs/RELEASING.md: pasos de lanzamiento para mantenedores.
- CHANGELOG.md
Errores y preguntas: problemas de GitHub. Los problemas de seguridad se informan de forma privada: SECURITY.md. Configuración, comprobaciones y reglas para solicitudes de extracción: CONTRIBUTING.md.
Licencia
MIT, ver LICENSE. Cubre este código solamente, no el servicio de Fitatu, su API o los datos que devuelve.