Skip to main content
Glama
derikkruger

opengym-conector

by derikkruger

opengym-conector

Conector MCP remoto para o openGym. Cada pessoa da instância gera um link pessoal e cola no Claude (conector personalizado) ou no ChatGPT (modo desenvolvedor). A partir daí dá para planejar treinos, registrar o que fez e analisar o progresso conversando, e tudo é gravado pela API oficial do openGym, então aparece em todos os aparelhos da pessoa como se tivesse sido feito no app.

Licença e código do openGym

Este projeto é AGPL-3.0-or-later (texto em LICENSE), porque reaproveita código do openGym, que é AGPL-3.0:

  • upstream: https://github.com/DuarteSantos8/openGym, tag v1.4.1, commit 464355ef43d4c8f8a4e0bb6db9c2af7f240593b5;

  • o código do openGym não está copiado neste repositório: scripts/baixar-opengym.mjs faz um clone esparso da tag (pastas mcp, frontend/src/lib, frontend/src/exercise-names), confere o hash do commit e grava em ./upstream, no build da imagem ou antes dos testes;

  • um único arquivo do openGym é substituído: mcp/src/state.js, pela versão em src/upstream-patch/state.js. O original lê ./data/state-<uid>.json do disco; o nosso recebe o estado lido da API a cada requisição (AsyncLocalStorage) e mantém todos os exports e o mesmo defaultsShape(). Nenhum outro arquivo do upstream é alterado;

  • tudo que é usado do upstream está listado em src/upstream.js.

Pela seção 13 da AGPL, quem usa o conector pela rede tem de poder obter o código-fonte. Publique este repositório e defina SOURCE_URL: as páginas passam a mostrar o link "código-fonte".

Related MCP server: strava-mcp

Variáveis de ambiente

Variável

Padrão

Para quê

OPENGYM_API

obrigatória

URL interna da API do openGym, por exemplo http://api:3000 na rede do compose

PUBLIC_URL

obrigatória

URL pública do conector, por exemplo https://ia.gym.bruxo.app; é o começo do link pessoal

PORT

8787

porta HTTP do container (o TLS fica no Traefik)

DATA_DIR

/data

onde fica conexoes.json (monte um volume)

TZ

America/Sao_Paulo na imagem

define o "hoje" de treinos e pesagens, como o relógio do aparelho

SOURCE_URL

vazio

link do código-fonte exibido nas páginas (AGPL)

Como um amigo conecta

  1. No navegador, entra no site do openGym com a conta dele.

  2. Configurações › Conta (a linha com o nome dele) › Parear o aplicativo. Aparece um código de 8 letras, que vale 5 minutos e só pode ser usado uma vez. (Rótulos conferidos no pacote pt-BR do openGym v1.4.1: Settings = Configurações, Account = Conta, Pair the mobile app = Parear o aplicativo. O item só aparece no site, não dentro do app de celular pareado.)

  3. Abre PUBLIC_URL/conectar, cola o código e recebe o link pessoal PUBLIC_URL/mcp/<chave>.

  4. Claude: Configurações › Conectores › Adicionar conector personalizado (Add custom connector), cola o link; na conversa, ativa no botão +. ChatGPT: Configurações › Apps › Configurações avançadas › Modo desenvolvedor; cria um conector com o link e autenticação "Sem autenticação" (No authentication).

Para cancelar: Sair de todos os dispositivos no openGym invalida o token, e o conector passa a responder com erro pedindo para conectar de novo.

Ferramentas

Leitura (as nove do MCP oficial do openGym, sem alteração, todas com readOnlyHint: true): list_routines, get_routine, preview_session, get_week_plan, list_workouts, get_workout, get_bodyweight, estimate_1rm, muscle_balance.

Novas:

Ferramenta

O que faz

Anotações

search_exercises

busca na biblioteca do app (~5600) e nos personalizados, por nome em inglês ou pt-BR, músculo, equipamento

leitura

create_routine

cria rotina (séries, reps, faixa, carga em kg, descanso, regra de progressão); recusa nome repetido

escrita

update_routine

renomeia, troca a lista de exercícios (mantendo nota, aquecimento e progressão de quem continua) e a progressão

escrita, destructiveHint

delete_routine

apaga a rotina e tira dos dias da semana, como o app

escrita, destructiveHint

set_week_schedule

põe rotinas nos dias da semana fixa; em modo rodízio recusa e explica, a menos que switch_to_fixed_week

escrita, idempotente

log_workout

registra treino já feito pelo caminho "Registrar um treino anterior" do app; repetição idêntica não duplica

escrita, idempotente

log_bodyweight

pesagem do dia; dia que já tem pesagem é corrigido

escrita, idempotente

Pesos entram em kg e são convertidos com as funções do app quando o perfil está em lb.

Como a sincronização é respeitada

O openGym mescla aparelhos campo a campo, com carimbo por mudança e registro de remoções (deleted, edited, _f, _ts; frontend/src/lib/sync-merge.js). Cada gravação do conector (src/sincronizar.js) faz o que o update() e o doPush() do app fazem (frontend/src/store/useStore.js):

  1. GET /api/data (documento, rev e _wid), sem cache entre chamadas;

  2. aplica a operação numa cópia, com as funções do próprio app (deleteRoutine, chooseFixedWeek, buildCombinedEntries, buildCompletedWorkout, completeBackfill, rebuildPrHistory, refillAfter, ...);

  3. carimba com stampChange(anterior, novo) do app e põe o tempo em _ts;

  4. PUT /api/data com baseRev, baseWid e stamped: true;

  5. no 409 a API devolve o documento atual e a operação é reaplicada sobre ele, até 3 vezes. Gravações do mesmo perfil passam por uma fila, então o 409 só vem de outro aparelho.

Os testes provam com o mergeStates do app que um aparelho com cópia velha mantém as gravações do conector e que nada apagado (por ele ou pelo conector) volta.

Segurança

  • A chave pessoal são 32 bytes aleatórios (base64url) e só existe no link. No disco, conexoes.json guarda sha256(chave) para achar o registro e o token do openGym cifrado com AES-256-GCM, numa chave derivada por HKDF da própria chave pessoal. O arquivo vazado sozinho não abre nenhum token.

  • O link funciona como senha (é um bearer na URL). Quem tiver o link lê e altera os treinos daquela pessoa, e só dela. A página avisa isso.

  • Nunca vão para o log: chave, token, código de pareamento, corpo de requisição. Atenção ao Traefik: se o access log estiver ligado, ele grava o caminho /mcp/<chave>. Desligue o access log desse roteador ou filtre o caminho.

  • Limites: 60 pedidos MCP por minuto por link, 10 pareamentos por minuto por endereço (último item do X-Forwarded-For), corpo MCP até 1 MB.

  • O token do openGym vale 90 dias (SESSION_DAYS); passados ~40, o conector consulta GET /api/me no máximo uma vez por hora e guarda o token novo que a API devolve depois de 45.

  • "Sair de todos os dispositivos" no openGym encerra todos os links da pessoa.

Rodando junto do openGym (compose)

O conector precisa estar na mesma rede Docker do serviço api do openGym (porta 3000):

services:
  conector:
    build: ./opengym-conector
    restart: unless-stopped
    depends_on:
      - api
    environment:
      OPENGYM_API: http://api:3000
      PUBLIC_URL: https://ia.gym.bruxo.app
      DATA_DIR: /data
      PORT: "8787"
      TZ: America/Sao_Paulo
      # SOURCE_URL: https://endereco-publico-deste-repositorio
    volumes:
      - conector-data:/data
    labels:
      - traefik.enable=true
      - traefik.http.routers.opengym-ia.rule=Host(`ia.gym.bruxo.app`)
      - traefik.http.routers.opengym-ia.entrypoints=https
      - traefik.http.routers.opengym-ia.tls=true
      - traefik.http.services.opengym-ia.loadbalancer.server.port=8787

volumes:
  conector-data:

Se o openGym estiver em outro projeto compose, ligue os dois a uma rede externa em comum e use o nome do container da API em OPENGYM_API. Prefira volume nomeado: o processo roda como node (uid 1000), e um bind mount precisa pertencer a esse uid.

Desenvolvimento

npm ci
npm test

npm test baixa o openGym v1.4.1 com api/ (npm ci --omit=optional dentro dela), sobe api/server.js de verdade na porta 3999 numa pasta temporária, cria o perfil sem navegador (como os testes do próprio openGym: db.json semeado e sessão assinada com o secret), gera um código de pareamento, pareia, chama cada ferramenta pelo cliente MCP do SDK e confere no GET /api/data. CONECTOR_RAIZ=<pasta> roda o mesmo teste contra uma cópia montada como a imagem Docker.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables workout tracking and coaching within Claude conversations, managing exercise configs, logs, streaks, and health metrics via an MCP server with PostgreSQL.
    -
  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables Claude or ChatGPT to act as a personalized fitness coach with persistent goals, conversational workout logging, and weekly generated training plans.
    -