Skip to main content
Glama

technogym-mcp

An MCP server that gives AI assistants read access to your Technogym mywellness training history: workout sessions, per-exercise data with per-set reps / weight / rest, per-second exercise analytics (machine channels + heart rate) and whole-session heart-rate traces.

It runs as a persistent local HTTP server that starts with Windows, so every MCP client on the machine (Claude Desktop, Claude Code, Cursor, ...) can connect to the same endpoint.

How it works / caveat. Technogym's official API is partner-only (B2B). This server speaks the same JSON API the official end-user web app (endusernext.mywellness.com) uses, logging in with your normal email + password and identifying itself with that app's client headers. No HTML scraping is involved, but it will still break if Technogym changes the login flow or the client-trust rules. The old mywellness.com/cloud portal that earlier tools (e.g. lcanis/gymexport) scraped was retired in 2026 and now redirects to technogym.com.

Tools

Tool

What it returns

get_account_info

Logs in and returns user id, name, culture, facilities and current Movergy score. Use to verify credentials.

list_workout_sessions(from_date?, to_date?, only_workouts=true)

Sessions in a range (default: last 30 days), newest first: session_id, date, time, name, duration, MOVEs, calories, exercise counts.

get_workout_session(session_id, date?)

Every exercise with machine, status, duration, calories, MOVEs, muscles, performed and prescribed sets (reps, kg, rest), plus session efficacy and muscle scores.

get_recent_workouts(days=14)

Lists and fully loads all sessions from the last N days.

get_exercise_analytics(analytics_id, sample_every_seconds=1)

Per-second machine channels, HR samples, HR zones and summary metrics (total weight, est. 1RM, METs...) for one exercise.

get_session_heart_rate(session_id, date?, sample_every_seconds=10)

Timestamped HR trace, HR zones and avg/min/max HR for a whole session.

A session is addressed by session_id and its date (the API partitions by day). Pass the date whenever you have it; if omitted, the last year of history is scanned to find it.

GET /health on the same port reports liveness and whether a session is authenticated.

Setup

Requires uv (it manages Python for you).

git clone https://github.com/ErikAnkerKilbergSkallevold/technogym_mcp
cd technogym_mcp
copy .env.example .env      # then fill in MYWELLNESS_EMAIL / MYWELLNESS_PASSWORD
uv sync

Run once (foreground)

uv run technogym-mcp                   # HTTP on http://127.0.0.1:8765/mcp
uv run technogym-mcp --transport stdio # for clients that spawn the server themselves

Start with Windows (always available)

powershell -ExecutionPolicy Bypass -File scripts\install-startup.ps1

This registers a Scheduled Task named Technogym MCP Server that starts silently at logon (via uvw.exe, no console window), restarts on failure, and never times out. Logs go to logs\technogym-mcp.log. Remove it with scripts\uninstall-startup.ps1. After editing .env, restart it: Restart-ScheduledTask "Technogym MCP Server".

Expose it publicly (Cloudflare Tunnel)

To reach the server from other machines or from a hosted Claude, tunnel it out through Cloudflare instead of opening a port. One-time prerequisites:

winget install Cloudflare.cloudflared
cloudflared tunnel login            # browser: pick your zone

Set TECHNOGYM_MCP_PUBLIC_HOST=technogym.example.com in .env, restart the server task, then:

powershell -ExecutionPolicy Bypass -File scripts\install-tunnel.ps1 -Hostname technogym.example.com

This creates a named tunnel, routes the DNS record, and installs cloudflared as a Windows service (it will ask for elevation once). The MCP endpoint is then https://technogym.example.com/mcp.

Alternatively, create the tunnel in the Zero Trust dashboard (Networks → Tunnels → Create, choose Windows, run the provided cloudflared service install <token> command) and add a public hostname there pointing at http://localhost:<port>. That also installs an auto-starting Windows service; skip the script in that case, since it would create a second tunnel.

The MCP endpoint has no authentication of its own. Pick one of two ways to protect it:

  • Cloudflare Access (best when your clients can complete a browser login, e.g. Claude Code with claude mcp add --transport http): add an Access application for the hostname (Zero Trust → Access → Applications → Self-hosted) with a policy that allows only your email.

  • Unguessable path (needed for clients that cannot send auth headers or do a Cloudflare login, e.g. claude.ai custom connectors): set TECHNOGYM_MCP_PATH=/<32 random hex>/mcp in .env, restart the server task, and treat the full URL as a secret. Requests to any other path get 404. Optionally still put Access on /health and /.

Adding to claude.ai

  1. Make sure the tunnel is up and https://<host>/health answers.

  2. In claude.ai go to Settings → Connectors → Add custom connector.

  3. Name it Technogym, paste the full endpoint URL (https://<host><TECHNOGYM_MCP_PATH>), leave OAuth fields empty, and click Add.

  4. In a chat, open the tools menu (the sliders icon) and enable the Technogym connector.

Connecting a client

Claude Code

claude mcp add -s user --transport http technogym http://127.0.0.1:8765/mcp

Claude Desktop (claude_desktop_config.json), either pointing at the running server:

{
  "mcpServers": {
    "technogym": { "type": "http", "url": "http://127.0.0.1:8765/mcp" }
  }
}

or spawning it over stdio:

{
  "mcpServers": {
    "technogym": {
      "command": "uv",
      "args": ["run", "--directory", "C:\\path\\to\\technogym_mcp", "technogym-mcp", "--transport", "stdio"]
    }
  }
}

Configuration (.env)

Variable

Default

Purpose

MYWELLNESS_EMAIL

Your mywellness login

MYWELLNESS_PASSWORD

Your mywellness password

TECHNOGYM_MCP_HOST

127.0.0.1

Bind address. Keep on loopback; there is no auth on the MCP endpoint.

TECHNOGYM_MCP_PORT

8765

Port

TECHNOGYM_MCP_PUBLIC_HOST

Public hostname(s) accepted in the Host header, e.g. technogym.example.com, when exposed through a tunnel. The SDK's DNS-rebinding protection rejects unknown hosts with HTTP 421.

TECHNOGYM_MCP_PATH

/mcp

URL path of the MCP endpoint. Use an unguessable path when the endpoint must be reachable without auth headers (see claude.ai below).

TECHNOGYM_MCP_LOG_LEVEL

INFO

Logging level

API notes (for maintainers)

  • Login: POST https://core.mywellness.com/v2/enduser/authentication/login with {username, password, keepMeLoggedIn} and headers X-MWAPPS-APPID: EC1D38D7-D359-48D0-A60C-D8C0B8FB9DF9, X-MWAPPS-CLIENT: enduserweb. Returns token, userContext.id, facilities[].url.

  • Data: POST https://services.mywellness.com/{facilityUrl}/Training/User/{userId}/<Action> with Authorization: Bearer <token> and the same X-MWAPPS headers. Actions used: ActivityHistory, GetPerformedWorkoutSessionByIdCr, GetHrSession, MyMovergy; plus Training/CardioLog/{analyticsId}/Details. Dates are yyyyMMdd partition keys.

  • Localised strings (exercise names, units) come back in the account's culture.

Development

uv run pytest
uv run ruff check .

License

MIT