Fitatu
Servidor MCP não oficial para o Fitatu, o contador de calorias polonês: leia e registre alimentos, peso, água e treinos, verifique calorias e macronutrientes restantes e obtenha relatórios semanais. 40 ferramentas (23 somente leitura), modos somente leitura e demonstração, contas gratuitas e Premium. Python, no PyPI: uvx --from "fitatu-api[mcp]" fitatu-mcp
Documentação
fitatu-api
Um cliente Python não oficial para a API do Fitatu, o contador de
calorias, criado para ser usado por agentes de IA e scripts. Ele lê e escreve no diário alimentar,
atividades, medidas corporais e água, lê e define metas, e lê resumos e o catálogo de
alimentos.
FitatuTools transforma o diário em ferramentas que um modelo de linguagem pode chamar. O gerenciamento de sessão
segue o python-garminconnect: faça login uma vez,
mantenha um arquivo de sessão, deixe o cliente atualizá-lo.
Não oficial. Este projeto não é afiliado ou endossado pela Fitatu Sp. z o.o. A API foi engenharia reversa dos aplicativos Fitatu e pode mudar sem aviso. O acesso automatizado pode violar os Termos de Serviço da Fitatu; verifique-os e use a biblioteca apenas com sua própria conta e por sua conta e risco. A licença MIT cobre este código, não o serviço Fitatu, sua API ou seus dados.
Instalação
Python 3.11 ou mais recente; a única dependência é requests (e tzdata no 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 trabalhar na biblioteca ou executar seus testes offline, clone-a: git clone https://github.com/Jezue/fitatu_library && cd fitatu_library && pip install -e ".[dev]".
Início rápido
fitatu-api login # asks for e-mail and password, writes ~/.fitatu/session.json
Cadastrou-se com Apple ou Facebook? Então a conta não tem senha: copie a sessão do
aplicativo web com fitatu-api import-session em vez disso, conforme descrito em
Autenticação e arquivo de sessão.
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"])
Como funcionam gravações, IDs de linha e remoções: docs/PLANNER.md.
Para copiar o menu de uma dieta de catering para o diário (seguro de executar novamente), use catering_sync.py do
repositório: Importando um menu de catering.
Para agentes de IA
FitatuTools expõe 47 ferramentas (ler o dia, pesquisar alimentos, registrar alimentos, peso, água,
treinos, receitas e produtos privados, ...) com entradas de JSON Schema e anotações somente leitura / destrutivas / idempotentes.
call() nunca lança exceções: retorna {"ok": true, "data": ...} ou {"ok": false, "error": {"error_type", "message", "retryable", "hint", ...}}, para que o modelo possa ler o que deu errado.
SYSTEM_PROMPT é o prompt de sistema recomendado: as regras que o modelo precisa além das descrições
das ferramentas (ler antes de escrever, nomes de refeições dos usuários, data.ok, confirmações). O modelo
pergunta a get_today pela data, no fuso horário da conta.
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"))
As ferramentas de gravação (registrar alimentos, atualizar, mover, copiar e excluir linhas, peso, água, treinos, receitas
e produtos privados) precisam de um loop
que pergunte ao usuário antes de chamadas destrutivas; está em
docs/AGENTS.md, com a
tabela de ferramentas, as chamadas que nunca devem ser expostas (tokens de sessão, gravações no catálogo), como tornar as gravações seguras
de repetir, o que fazer por error_type, a variante OpenAI, hosts de longa duração e como testar
as ferramentas sem uma conta contra o backend de teste offline.
MCP
fitatu-mcp serve as mesmas ferramentas para Claude Code, Claude Desktop e outros hosts MCP via
stdio, com SYSTEM_PROMPT como suas instruções e três comandos de barra em polonês
(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 serve as mesmas ferramentas via HTTP, com um token, para n8n, outro computador ou
Docker (o repositório tem um Dockerfile):
docs/AGENTS.md.
Sem uma conta, fitatu-mcp --demo (ou FitatuTools.demo()) serve um pequeno diário fictício
mantido em memória. Para Claude Desktop, cada lançamento do GitHub
tem fitatu-<version>.mcpb, instalado com um clique duplo (faça login com fitatu-api login primeiro). Sem instalar nada, uvx --from "fitatu-api[mcp]" fitatu-mcp executa o servidor. Ele está
listado no Registro MCP como
io.github.Jezue/fitatu-api (server.json). Para Hermes Agent e outros hosts que leem
Agent Skills, skills/fitatu-diary/SKILL.md
diz ao agente como configurar o servidor e usar bem suas ferramentas.
O prompt de permissão do host é a etapa de confirmação, então mantenha-o ativado para as ferramentas destrutivas. Claude Desktop, uvx e o que o servidor faz: docs/AGENTS.md.
O que cobre
| Área | Cliente (FitatuApiClient) | Ferramentas de agente |
|---|---|---|
| Diário alimentar | client.planner: ler um dia, adicionar produtos, receitas, linhas personalizadas e resultados de pesquisa, atualizar, mover, copiar, remover; a nota do dia | get_day, add_food, add_foods, add_custom_item, update_item, move_item, copy_meal, preview_removal, remove_items, set_note |
| Atividades | planner.add_activity / remove_activity, client.activities (catálogo, pesquisa, recentes) | search_activity, add_activity, remove_activity |
| Alimentos | search_food, get_product_details, get_recipe, catálogo de receitas e sua pesquisa, client.foods (favoritos, recentes) | search_food, search_recipes, get_recipe, find_by_barcode, get_food_measures, get_recent_foods, get_favorite_foods, set_favorite |
| Alimentos próprios do usuário | search_user_food, create_product, update_product, delete_product, create_recipe, update_recipe, delete_recipe | get_my_foods; create_food, update_food, delete_food e as ferramentas de receita apenas para alimentos privados do próprio usuário |
| Medidas | client.measurements: peso e medidas corporais por dia, histórico, gráficos | get_weight_history, get_body_measurements, get_measurement_history, log_weight, log_measurements |
| Água | client.water | get_water, set_water |
| Resumo e exportação | client.summary: totais de intervalo, nutrientes por dia, principais produtos, exportação do diário | get_range_summary, get_progress, get_top_foods, get_report, get_shopping_list (calculado a partir das linhas planejadas) |
| Jejum e hábitos | client.fasting (esquemas, períodos de alimentação por dia), client.habits (catálogo, hábitos do usuário, bons dias); somente leitura | get_fasting, get_habits, get_good_days |
| Metas e configurações | client.user_settings: alvos, BMR/TMR, perfil | get_targets, set_targets (a meta manual ou automática, divisão de macronutrientes, tamanho do copo), get_profile (altura, peso, meta, IMC, Premium; nada que identifique o usuário) |
| Gravações no catálogo | create_recipe(shared=True), set_product_proposal, limpeza de duplicatas | nenhuma, de propósito |
FitatuLibrary, que envolve a maioria desses como métodos *_via_api que retornam {"status": ...}
em vez de lançar exceções, está obsoleto e será removido na versão 1.0: para resultados que nunca lançam exceções, use
FitatuTools ({"ok": true, "data": ...}), caso contrário, o cliente. Cada chamada pública com sua estabilidade está listada em
docs/API_REFERENCE.md.
Contas gratuitas e Premium
| Conta gratuita | Premium | |
|---|---|---|
| Diário: ler, registrar, atualizar, mover, copiar, remover alimentos, notas, atividades, água, peso, medidas corporais | ✅ | ✅ |
Pesquisa, código de barras, medidas de alimentos, pesquisa de receitas por palavras e max_energy_kcal, receitas completas, receitas e produtos privados, favoritos, alimentos recentes | ✅ | ✅ |
Filtros de pesquisa de receitas (min_protein_g, max_carbohydrate_g, max_cooking_time, diets, meal) e receitas premium do catálogo (get_recipe, get_food_measures, add_food, add_foods; a lista de compras omite seus ingredientes) | ❌ "precisa do Fitatu Premium": as ferramentas seguem o aplicativo | ✅ |
Metas: ler e definir (get_targets, set_targets), progresso (get_progress), relatórios (get_report), totais de intervalo (get_range_summary) | ✅ (progresso: uma solicitação por dia, no máximo 31 dias) | ✅ |
| Histórico de peso e medidas corporais, perfil, jejum e hábitos (leitura), lista de compras | ✅ | ✅ |
Principais alimentos (get_top_foods, summary.get_top_products()) | ❌ 403: precisa do Fitatu Premium | ✅ |
Exportação do diário (fitatu-api export, summary.export_diary()) | ❌ 403: "precisa do Fitatu Premium" | ✅ |
Proteína / gordura / carboidrato dia a dia (summary.get_nutrient_by_day(); energia funciona em ambos) | ❌ 403 (get_progress contorna isso) | ✅ |
Quase tudo funciona em uma conta sem Fitatu Premium. A Fitatu responde 403 sem ele para (verificado ao vivo em 2026-10-15):
summary.get_nutrient_by_day()para proteína, gordura e carboidrato (energia funciona em qualquer conta);summary.get_top_products(), e portanto a ferramentaget_top_foods;summary.export_diary(), e portantofitatu-api export, que então diz isso em uma linha.
A Fitatu serve os filtros de pesquisa de receitas e receitas premium do catálogo para qualquer conta, mas seu aplicativo
os mantém para Premium, e as ferramentas também: elas verificam os flags accessControl da conta e
respondem com um erro forbidden sem eles. O cliente em si não verifica.
get_progress e get_report funcionam em todas as contas: quando a rota dia a dia de macronutrientes é
recusada, eles leem o resumo de cada dia em vez disso (uma solicitação por dia, no máximo 31 dias), e
get_report dá top_foods nulo com um top_foods_note. As metas de macronutrientes de uma conta gratuita são um
intervalo (target_min abaixo de target_max); em uma conta Premium, um resumo de um dia deu os dois
iguais (a rota dia a dia get_progress lida lá concorda, verificado ao vivo). Ele também aceita uma meta manual e sua própria divisão de macronutrientes (set_targets, verificado ao vivo em 2026-10-15); com uma divisão, suas
metas de macronutrientes são números únicos. fitatu-api doctor
diz se a conta tem um plano premium. Veja
Contas gratuitas e Premium
em docs/AGENTS.md para as ferramentas.
Linha de comando
fitatu-api (também python -m fitatu_api) funciona no arquivo de sessão, $FITATU_SESSION ou
~/.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 onde vem a sessão (o arquivo e suas permissões, ou
$FITATU_SESSION_JSON), o ID do usuário, host da API, localidades, quando o token de portador expira e
se há um token de atualização, sem enviar nada; --check também lê o perfil
uma vez. doctor verifica a configuração com a Fitatu, uma linha ok / WARN / FAIL cada: as permissões
do arquivo de sessão, o token de atualização (ele atualiza o token de portador uma vez e o salva, como qualquer
atualização faz), o relógio deste computador contra o tempo de emissão do token novo, uma leitura de perfil,
se um plano premium está ativo (não até quando, nem seu preço), e se o aplicativo web da Fitatu ainda está na versão que a biblioteca envia (GET /upgrade-application/WEB/<version>); ele sai com 1 quando uma verificação falha e não imprime
token, ID do usuário ou diretório inicial, então sua saída pode ir para um relatório de bug. logout exclui o
arquivo de sessão; pare fitatu-mcp e outros processos que o usam primeiro, pois eles escreveriam
seus tokens atualizados de volta. A Fitatu não tem nenhuma chamada conhecida pela biblioteca que revogue tokens.
Nenhum desses comandos imprime um token. fitatu-api --version imprime a versão.
call executa uma ferramenta via FitatuTools.call() e imprime seu envelope como JSON; o status de
saída é 0 quando ok é verdadeiro e 1 quando é falso. Apenas as ferramentas de leitura (READ_ONLY_TOOLS)
são executadas a menos que --allow-writes seja fornecido. export salva a exportação do diário da Fitatu (csv, xls, pdf
ou txt) em um novo arquivo legível apenas por você (0600); ele não substitui um arquivo existente
sem --overwrite, e um intervalo sem nada registrado não escreve arquivo e sai com 1.
fitatu-api COMMAND --help descreve cada comando. Os logs vão para stderr, a partir de WARNING, a menos que
fitatu-api --log-level DEBUG COMMAND ou FITATU_LOG_LEVEL diga o contrário (veja
Privacidade e registro).
Autenticação e arquivo de sessão
fitatu-api login [--email ADDRESS] [-o PATH] [--base-url URL] (também python -m fitatu_api login) faz login, lê seu perfil para as localidades e fuso horário da conta e escreve o
arquivo de sessão. Ele lê FITATU_EMAIL e
FITATU_PASSWORD quando estão definidos e solicita caso contrário. Contas sem senha usam
fitatu-api import-session (abaixo).
-
Onde.
fitatu-api login,fitatu-api import-session,FitatuApiClient.from_session(),FitatuTools.from_session()e o obsoletoFitatuLibrary.from_session()usam o mesmo arquivo: o caminho que você passa (-opara a CLI), senão$FITATU_SESSION, senão$FITATU_SESSION_PATH, senão~/.fitatu/session.json. Um arquivo ausente geraFitatuAuthErrorinformando para você executarfitatu-api login. -
O quê. JSON com
bearer_token,refresh_token,fitatu_user_id,base_url(o host da API da região),app_locale,app_searchlocale,app_storagelocale,app_timezonee uma versão de esquema. A identidade do cliente (chave de API, versão do app, ...) não é armazenada; ela vem da biblioteca. -
Permissões. O arquivo é gravado somente pelo proprietário (0600), em um diretório criado com 0700, através de um arquivo temporário que o substitui, então um leitor nunca vê meia sessão. Ele contém tokens ativos: trate-o como uma senha.
-
Tokens. Verificados ao vivo em 2026-10-13: o token bearer é um JWT que dura uma hora. O token de atualização é uma string opaca que o Fitatu não rotaciona:
POST /token/refreshretorna um novo token bearer e o mesmo token de atualização, que continua funcionando, e tokens bearer mais antigos permanecem válidos até expirarem.POST /loginresponde a um e-mail ou senha errados com 422, não 401. -
Atualização e gravação de volta. O cliente atualiza o token bearer 60 segundos antes de ele expirar (do JWT
exp) e uma vez após um 401, uma atualização por vez. Os tokens são mesclados no arquivo de sessão, então o próximo processo começa com eles; um processo que compartilha o arquivo pega um par que outro salvou, por exemplo, apósfitatu-api loginser executado novamente. Passepersist_tokens=Falsepara manter o arquivo intocado. Um par de outra conta (um login em outra conta com o mesmo arquivo) não é pego: o cliente em execução mantém seus próprios tokens e para de gravar no arquivo, então esse login permanece. Quando um token recém-obtido do Fitatu já parece expirado, o relógio do computador está adiantado: o cliente então registra um aviso e atualiza somente após um 401. -
Fazendo login novamente. Quando o Fitatu rejeita o token de atualização, as chamadas geram
FitatuAuthError(error_typeauth). Executefitatu-api login(ouimport-session) novamente; um cliente em execução pega o novo par do arquivo na próxima vez que precisar de uma atualização. -
Contas sem senha. Contas criadas com Apple ou Facebook (endereços "Ocultar meu e-mail" da Apple incluídos) não têm senha para
fitatu-api login. Copie a sessão do aplicativo web em vez disso:-
Faça login em https://www.fitatu.com/app/ com Apple ou Facebook.
-
Abra o console do desenvolvedor do navegador nessa página e execute a linha abaixo. Ela copia apenas os tokens e seu ID de usuário; o
localStorage.userdo aplicativo web também contém seu e-mail, apelido e mais.copy(JSON.stringify((u => ({token: u.token, refresh_token: u.refresh_token, id: u.id}))(JSON.parse(localStorage.user)))) -
No macOS, execute
pbpaste | fitatu-api import-session. No Linux ou Windows, cole-o em um arquivo, executefitatu-api import-session < file(PowerShell:Get-Content file | fitatu-api import-session) e exclua o arquivo.
import-session [-o PATH] [--base-url URL]lê o JSON da entrada padrão (um arquivo de sessão desta biblioteca também funciona), verifica ambos os tokens com o Fitatu atualizando o bearer uma vez (então o salvo é válido por uma hora), lê os locais e o fuso horário da conta comologine grava o arquivo de sessão da mesma forma. Nada mais da entrada é salvo. O token é uma credencial completa da conta: não o cole em nenhum outro lugar. -
-
Contêineres e cron. Onde nenhum arquivo de sessão gravável cabe, coloque o próprio JSON da sessão em
FITATU_SESSION_JSON:fitatu-api login --print(ouimport-session --print) o imprime na saída padrão em vez de gravar um arquivo, para um armazenamento de segredos.from_session()sem um caminho o pega antes de qualquer arquivo e mantém os tokens que atualiza na memória: o Fitatu não rotaciona o token de atualização, então o mesmo valor funciona para cada execução até que o token de atualização em si expire (quanto tempo ele vive ainda não é conhecido) ou você faça login novamente. -
Fachada (obsoleta).
FitatuLibrary.from_session()carrega o mesmo arquivo e grava tokens atualizados de volta nele.FitatuLibrary(session_data, session_path=...)faz o mesmo para um dict de sessão e copia o par atual emsession_dataapós cada chamada. -
Do Python.
FitatuApiClient.login(email, password, token_store_path=path)faz login e mescla toda a sessão empath.
Regiões e cabeçalhos
O host da API é o base_url da sessão, senão o host do local de armazenamento da conta:
pl_PL torna-se https://pl-pl.fitatu.com/api, de_DE torna-se https://de-de.fitatu.com/api.
fitatu-api login faz login em https://pl-pl.fitatu.com/api e armazena o host do local de armazenamento;
com --base-url ele faz login lá e armazena essa URL.
| Grupo | Cabeçalhos | Notas |
|---|---|---|
| Obrigatórios | API-Key, API-Secret, Authorization: Bearer <jwt> | A chave e o segredo são valores estáticos do app (403 sem eles); Authorization é necessário em rotas de usuário (401). |
| Semânticos | APP-SearchLocale, APP-Locale, APP-StorageLocale, APP-Timezone | APP-SearchLocale e o parâmetro de consulta locale alteram os resultados de pesquisa. Os outros descrevem o usuário. Todos os quatro vêm da sessão, que login() preenche a partir do perfil; uma sessão sem eles envia os padrões pl_PL / Europe/Warsaw. |
| Identificação | APP-OS, APP-Version, APP-UUID, API-Cluster, User-Agent | Apenas identificam o cliente. A biblioteca sempre envia um perfil constante do aplicativo web (WEB_CLIENT_PROFILE em constants.py), nunca armazenado em sessões. |
Se o Fitatu mudar o que o aplicativo web envia (sua versão, ou a chave e o segredo da API) antes de um
lançamento da biblioteca seguir, defina FITATU_CLIENT_PROFILE para um objeto JSON com as chaves de
WEB_CLIENT_PROFILE para alterar, por exemplo, FITATU_CLIENT_PROFILE='{"app_version": "4.14.0"}'. Qualquer
outra chave ou um valor que não seja texto simples é recusado com um FitatuValidationError
(fitatu-mcp então não inicia). fitatu-api doctor diz se a versão ainda é a mais
nova.
Login (POST /login com _username e _password) e atualização (POST /token/refresh com
{"refresh_token": ...}) passam pelo mesmo caminho de solicitação e enviam os mesmos cabeçalhos, sem
Authorization; no login, os cabeçalhos de local ainda são os padrões pl_PL. Não há
assinatura de solicitação, e o Firebase App Check não é aplicado; a biblioteca não o envia.
Credenciais só vão para hosts https sob fitatu.com: qualquer outro base_url ou URL absoluta
gera FitatuValidationError antes que uma solicitação seja feita, e Authorization só é enviado para
URLs sob base_url ou https://fitatu.com/api. Redirecionamentos não são seguidos: uma resposta 3xx é
um FitatuApiError, então um corpo de solicitação nunca vai para outro host.
Erros, tentativas, limites de taxa
Os erros da biblioteca são subclasses de FitatuApiError. describe_error(exc) transforma qualquer
exceção no dict seguro para JSON que FitatuTools.call() (e o obsoleto FitatuLibrary) retornam.
| Exceção | Gerada quando | error_type |
|---|---|---|
FitatuValidationError (também um ValueError) | Um argumento é inválido; nada foi enviado. | validation |
FitatuNotFoundError | O id, refeição ou linha que você nomeou não está lá: a biblioteca encontrou isso no que leu (a mensagem lista o que está lá), ou o servidor respondeu 404 (status_code 404). | not_found |
FitatuAuthError | 401 após uma atualização, um token de atualização rejeitado, nenhum arquivo de sessão, ou um e-mail ou senha errados no login (o Fitatu responde 422); hint então aponta para import-session. | auth |
FitatuRateLimitError | 429 após tentativas; retry_after contém a espera do servidor em segundos. | rate_limit |
FitatuConnectionError | Nenhuma resposta HTTP (DNS, timeout, conexão redefinida). | network |
FitatuMaintenanceError | O cabeçalho technical-break do Fitatu; display_from / display_to. | maintenance |
FitatuPlannerSyncError | A sincronização do dia respondeu 202 mas rejeitou um dia; results tem os erros por dia. | sync_rejected |
FitatuPremiumRequiredError | Uma ferramenta para o que o app Fitatu mantém para Premium, em uma conta sem ele; nada foi enviado para isso. | forbidden |
FitatuApiError | Qualquer outro erro HTTP: status_code, body, codename (por exemplo, NUMBER_OF_USES_EXCEEDED). | forbidden (403), validation (400/409/422), server |
Mensagens leem METHOD /path -> status CODENAME: server message. Na mensagem de describe_error(),
o ID do usuário é <user> (GET /diet-plan/<user>/days -> 403), e com user_id= (que
FitatuTools.call() passa) onde quer que apareça, então um resultado não o carrega para o
provedor de modelo. Um 403 cujo corpo é uma página HTML vem de um firewall na frente da API (por exemplo,
Cloudflare), não das verificações de premium ou chave do Fitatu, e seu hint diz isso. Qualquer outra exceção, como um TypeError gerado dentro da
biblioteca, é unexpected: um bug para relatar, já que FitatuTools.call() verifica os argumentos primeiro.
Tentativas: erros de rede, 429, 500/502/503/504 e 520 a 524 do Cloudflare são tentados novamente por GET, HEAD e OPTIONS,
e para gravações marcadas como idempotentes: a sincronização do dia (todas as gravações do planejador; ela faz upsert por ID de linha),
water.set_day, measurements.set_day, measurements.delete_day e foods.set_favorite.
Outras gravações (gravações de catálogo, configurações, login, atualização) são enviadas uma vez. Até
retry_max_attempts=3 tentativas com backoff exponencial de retry_base_delay_seconds=0.5.
Um Retry-After de até 30 segundos é respeitado; um mais longo não é esperado, e o erro
é gerado imediatamente (FitatuRateLimitError com retry_after para um 429). Durante uma pausa
técnica, nada é tentado novamente ou atualizado. Dentro de with client.time_limit(seconds):, as solicitações
terminam dentro desse tempo no total: uma tentativa cuja espera deixaria menos de 2 segundos não é feita, o timeout de cada
solicitação é reduzido para o tempo restante, e uma solicitação sem tempo restante não é enviada
(FitatuConnectionError). FitatuTools executa cada chamada em um de 45 segundos (call_timeout).
A maioria das gravações faz várias solicitações, o que conta quando você faz orçamento contra 429s: as ferramentas leem
o dia antes de cada gravação de diário, e atualizações, movimentos, remoções e gravações de atividade o leem
novamente depois para definir ok. Solicitações por chamada de ferramenta do agente, antes de tentativas e atualizações de token:
| Solicitações | Ferramentas |
|---|---|
| 0 | get_today |
| 1 | as outras ferramentas de leitura; set_water; set_favorite; preview_removal e remove_items com dry_run; delete_recipe de uma receita já excluída, delete_food de um produto já excluído |
| 2 | get_range_summary, get_profile, get_fasting (3 quando as configurações nomeiam o esquema por id), get_habits, find_by_barcode (1 sem um resultado de produto), add_food para uma receita em porções (mais 1 para os sinalizadores Premium, a primeira chamada desse tipo em 10 minutos; sem Fitatu Premium, mais 1, pois lê a receita primeiro), add_custom_item, log_weight, delete_recipe, set_targets, create_food, delete_food; add_foods, mais 1 para cada item com unit ou measure_id e, sem Fitatu Premium, para cada receita em porções (e 1 para os sinalizadores Premium como em add_food); create_recipe, mais 1 para cada ingrediente; search_recipes com um filtro, mas max_energy_kcal, e get_recipe e get_food_measures de uma receita premium, a primeira chamada desse tipo em um FitatuTools em 10 minutos (lê os sinalizadores Premium da conta; 1 depois) |
| 3 | add_food com unit ou measure_id (lê o alimento primeiro), log_measurements (lê a unidade de medida do perfil), copy_meal dentro de um dia, remove_items, add_activity, remove_activity, set_note, update_food; update_recipe, mais 1 para cada novo ingrediente |
| 4 | update_item, move_item dentro de um dia, copy_meal para outro dia |
| 5 | get_progress (qualquer intervalo de até 62 dias; sem Fitatu Premium, veja abaixo) |
| 6 | move_item para outro dia |
| 8 | get_report (mais um para cada 41 pesagens adicionais no intervalo) |
| 1 por dia | get_shopping_list, mais 1 para cada receita planejada no intervalo (e 1 para os sinalizadores Premium quando uma é premium); get_progress e get_report sem Fitatu Premium, mais 1 para o intervalo (nenhum para um único dia) e as pesagens de get_report, e a primeira chamada desse tipo em um FitatuTools em 10 minutos, mais 1, que o Fitatu recusa |
Privacidade e registro
A biblioteca registra por meio do módulo padrão logging e não configura manipuladores. O
comando fitatu-api e fitatu-mcp registram em stderr, nunca em stdout (que carrega o
resultado do comando, ou o protocolo MCP): a biblioteca a partir de WARNING, ou do nível 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 define; outras bibliotecas a partir de WARNING.
INFO(fitatu_api.client): eventos de autenticação como linhas JSON: login (id do usuário), início de atualização de token, sucesso e falha, eclear_auth, com um instantâneo de estado não secreto (id do usuário, locais, fuso horário, host, expiração do token, se os tokens estão presentes).WARNING(fitatu_api.client):fitatu.request.errorpara uma solicitação que falhou definitivamente em um erro de rede, um 429 ou um 5xx, após suas tentativas;fitatu.auth.clock_skew(um token fresco do Fitatu parece expirado, então o relógio local está errado; atualizar antes da expiração para) efitatu.auth.store_other_account(o arquivo de sessão agora contém os tokens de outra conta; o cliente mantém os seus próprios). Defitatu_api.agent,fitatu_api.facadeefitatu_api.mcp_server, uma chamada cujo resultado relata um errounexpected(com o traceback), umauthou um erromaintenance:get_day failed (auth): .... Defitatu_api.auth, um armazenamento de tokens (geralmente o arquivo de sessão) que não pôde ser lido. Defitatu_api.mcp_serversob--http, cada solicitação recusada por seu token, com o endereço do cliente (nunca o token); o uvicorn adiciona suas linhas de início e parada.DEBUG(fitatu_api.client): cada solicitação como linhas JSON:fitatu.request.start(método, caminho, parâmetros de consulta, como frases de pesquisa),fitatu.request.retryantes da espera de cada tentativa (oattemptfalhou,delay_seconds, e oreason: o status ou o tipo de erro de rede), entãofitatu.request.okoufitatu.request.error(status,attempt,elapsed_msdesde o início, e os primeiros 300 caracteres de um corpo de erro; um 4xx permanece em DEBUG, pois o chamador o recebe como uma exceção e alguns, como um 404, são esperados). Defitatu_api.planner, uma linha por gravação do planejador (id do usuário, dia, refeição, id do alimento, o nome e kcal de uma linha personalizada); das camadas de ferramentas, todos os outros erros que um resultado relata. Caminhos contêm o id do usuário e datas.
Corpos de solicitação, senhas e tokens nunca são registrados: valores sob chaves contendo token,
secret, password ou authorization são substituídos por [redacted], e o contexto de autenticação
mantém tokens e o segredo da API fora de seu repr. Mensagens de erro carregam até 200 caracteres da
mensagem do servidor; o corpo completo da resposta está em exc.body, que describe_error() e
os resultados de erro de FitatuTools (e o obsoleto FitatuLibrary) deixam de fora. Um token que não é um valor de cabeçalho válido (por exemplo, colado com uma
nova linha) é relatado sem aspas.
Testes
pip install -e ".[dev]"
pytest -q
A suíte roda offline. tests/fixtures/api_recording.json contém respostas reais da API (limpas
de dados pessoais) para a sincronização do dia, medições, resumos, pesquisa e configurações;
tests/fake_server.py é um backend falso construído a partir delas, e tests/test_recorded_contract.py
falha se o falso se desviar da gravação. Como a gravação é feita e atualizada:
tests/fixtures/README.md.
A suíte ao vivo (tests/test_live_all.py) roda contra uma conta real e escreve nela:
FITATU_RUN_LIVE_TESTS=1 pytest tests/test_live_all.py
Ela usa o arquivo de sessão que fitatu-api login escreveu (ou $FITATU_SESSION) e salva
tokens atualizados de volta nele; com $FITATU_SESSION_JSON definido, essa sessão é usada em vez disso e
tokens atualizados não são salvos. Opcional: FITATU_LIVE_DAY (após hoje; padrão um ano a partir de
hoje), FITATU_LIVE_MEAL_KEY (snack), FITATU_LIVE_PRODUCT_ID, FITATU_LIVE_RECIPE_ID,
FITATU_LIVE_MEASUREMENT_DAY (2020-01-01; ignorado se tiver uma medição) e
FITATU_LIVE_RUN_WRITE_ACCOUNT=1.
Cada teste exclui exatamente as linhas que adicionou em FITATU_LIVE_DAY e falha se uma sobrar; um
dia em ou antes de hoje é recusado. Água e a nota naquele dia são restauradas, e o peso
e medições escritas em FITATU_LIVE_MEASUREMENT_DAY são excluídos. -k ReadOnly roda apenas
os testes que leem.
Registrar alimentos do catálogo os adiciona aos alimentos recentes da conta, o que não é desfeito. Com
FITATU_LIVE_RUN_WRITE_ACCOUNT=1 a suíte também altera e restaura o tamanho do copo de água e as
metas diárias (o Fitatu mantém as metas restauradas como uma nova versão a partir de hoje), e cria, depois
exclui, um produto privado e duas receitas privadas (uma pelas ferramentas, registrada em
FITATU_LIVE_DAY e removida) e um produto privado pelas ferramentas (registrado em
FITATU_LIVE_DAY, alterado, removido). Exclusões de produto e receita são suaves, então como os
alimentos recentes não são totalmente desfeitas: elas permanecem na conta, marcadas como excluídas e ocultas dos seus
alimentos e pesquisas. A lista completa está no docstring do módulo de tests/test_live_all.py. Nunca aponte FITATU_LIVE_DAY para um dia com entradas que você se importa.
scripts/check_contract.py informa, apenas lendo, se a API ao vivo ainda responde com a
estrutura que a gravação contém: imprime nomes de rotas e chaves, nunca valores, e sai com 1 quando uma
chave sumiu, um tipo mudou ou uma rota falha. O fluxo de trabalho Live contract o executa e os
testes ao vivo somente leitura toda segunda-feira com a sessão de uma conta descartável no segredo FITATU_SESSION_JSON,
e pula sem ele:
CONTRIBUTING.md.
scripts/eval_agent.py pontua quão bem um modelo Claude usa as ferramentas no diário de demonstração (29
tarefas em polonês e inglês; precisa de ANTHROPIC_API_KEY e custa uso de API, então CI não o
executa): docs/AGENTS.md.
Documentação
- docs/AGENTS.md: ferramentas, gravações seguras, tratamento de erros e o servidor MCP para agentes.
- docs/PLANNER.md: o contrato de sincronização do dia, ids e o resultado de cada gravação no diário.
- docs/API_REFERENCE.md: cada classe e método público com sua estabilidade.
- docs/APP_4_17_1_API_CATALOG.md: cada rota do aplicativo Android Fitatu 4.17.1, de uma descompilação.
- docs/RELEASING.md: etapas de lançamento para mantenedores.
- CHANGELOG.md
Bugs e perguntas: problemas do GitHub. Problemas de segurança são relatados em particular: SECURITY.md. Configuração, verificações e regras para pull requests: CONTRIBUTING.md.
Licença
MIT, veja LICENSE. Cobre este código apenas, não o serviço Fitatu, sua API ou os dados que ele retorna.