Skip to main content
Glama
opengym-conector

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: FitCoach 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.
    -
  • A
    license
    B
    quality
    B
    maintenance
    Enables AI assistants to read, log, edit, and analyze workouts, routines, body weight, media, and personal records on a self-hosted openGym instance through its own HTTP API. Writes are scoped to requested changes with automatic backups and conflict detection, and tools are grouped into read, write, delete, and admin permission tiers.
    74
    13 npm
    1
    AGPL 3.0