FitnessMCP
by senoj100-alt
README.md
# FitnessMCP
FitnessMCP is a production-ready remote [Model Context Protocol](https://modelcontextprotocol.io/) server that lets AI assistants work with fitness data from multiple services through one secure endpoint.
One server. One `/mcp` URL. Multiple fitness integrations.
## What It Connects
FitnessMCP currently includes tool groups for:
- **Hevy**: workouts, routines, exercise templates, routine folders, and workout events
- **Strava**: athlete profile, recent activities, and segment starring
- **Cronometer**: diary entries, daily nutrition, food search, food details, custom foods, macro targets, fasting history, and day completion
- **Intervals.icu**: athlete profile, activities, wellness, events, gear, reminders, and sport settings
It also includes high-level utility tools:
- `fitness_get_connected_services`
- `fitness_get_integration_plan`
## Why Use FitnessMCP
- **One MCP connection** instead of separate servers for each fitness app
- **Cloudflare Worker deployment** for a low-maintenance hosted endpoint
- **OAuth-ready MCP transport** for remote MCP clients
- **Encrypted credential storage** for user-supplied keys
- **No checked-in secrets**: all real credentials are supplied through Worker secrets or local-only files
- **Typed TypeScript codebase** with validation, tests, and CI
## Important Security Note
This repository intentionally does **not** include real API keys, tokens, passwords, KV namespace IDs, or personal credentials.
You will see placeholders such as:
```txt
replace_with_hevy_api_key
REPLACE_WITH_YOUR_PRODUCTION_KV_NAMESPACE_ID
```
That is expected. Replace those only in your own local `.dev.vars` file or in Cloudflare Worker secrets. Never commit real credentials.
## How The Pieces Fit Together
```mermaid
flowchart LR
A["AI assistant"] --> B["FitnessMCP /mcp endpoint"]
B --> C["Hevy client"]
B --> D["Strava client"]
B --> E["Cronometer client"]
B --> F["Intervals.icu client"]
B --> G["Cloudflare KV encrypted storage"]
```
## Beginner-Friendly Setup
This section assumes you are comfortable copying and pasting commands, but you do not need to be a professional developer.
### Step 1: Install The Required Apps
Install these first:
1. **Node.js** from [nodejs.org](https://nodejs.org/)
2. **Git** from [git-scm.com](https://git-scm.com/)
3. **A Cloudflare account** from [cloudflare.com](https://www.cloudflare.com/)
4. **A GitHub account** from [github.com](https://github.com/)
To check that Node.js and Git are installed, open Terminal and run:
```bash
node --version
git --version
```
If both commands print version numbers, you are ready.
### Step 2: Download The Project
Clone the repository:
```bash
git clone https://github.com/senojjones/FitnessMCP.git
cd FitnessMCP
```
Install the project dependencies:
```bash
npm install
```
### Step 3: Log In To Cloudflare From Terminal
Run:
```bash
npx wrangler login
```
Your browser will open. Sign in to Cloudflare and approve Wrangler.
### Step 4: Create Cloudflare KV Storage
FitnessMCP uses Cloudflare KV to store OAuth sessions and encrypted user credentials.
Run:
```bash
npx wrangler kv namespace create OAUTH_KV
```
Cloudflare will print something like:
```txt
{ binding = "OAUTH_KV", id = "abc123..." }
```
Copy the `id` value.
Open `wrangler.jsonc` and replace:
```txt
REPLACE_WITH_YOUR_PRODUCTION_KV_NAMESPACE_ID
```
with the KV namespace ID Cloudflare gave you.
For local development, you can use the same ID for:
```txt
REPLACE_WITH_YOUR_DEV_KV_NAMESPACE_ID
```
or create a second namespace:
```bash
npx wrangler kv namespace create OAUTH_KV --env dev
```
### Step 5: Create A GitHub OAuth App
FitnessMCP uses GitHub sign-in to identify users.
1. Go to [GitHub Developer Settings](https://github.com/settings/developers)
2. Click **New OAuth App**
3. Use this for local development:
```txt
Application name: FitnessMCP Local
Homepage URL: http://localhost:8787
Authorization callback URL: http://localhost:8787/callback
```
4. Click **Register application**
5. Copy the **Client ID**
6. Click **Generate a new client secret**
7. Copy the **Client Secret**
Keep these private.
### Step 6: Create Your Local Secret File
Copy the example file:
```bash
cp .dev.vars.example .dev.vars
```
Open `.dev.vars` in a text editor.
Replace:
```txt
GITHUB_CLIENT_ID=replace_with_your_github_oauth_client_id
GITHUB_CLIENT_SECRET=replace_with_your_github_oauth_client_secret
```
with your GitHub OAuth values.
Generate an encryption key:
```bash
openssl rand -hex 32
```
Copy the output and put it into:
```txt
COOKIE_ENCRYPTION_KEY=replace_with_64_character_hex_string
```
### Step 7: Add Fitness Service Credentials
You do not need every service. Configure only the apps you use.
#### Hevy
Get your API key from Hevy developer settings, then set:
```txt
HEVY_API_KEY=replace_with_hevy_api_key
```
#### Strava
Create a Strava app at [strava.com/settings/api](https://www.strava.com/settings/api), then set:
```txt
STRAVA_CLIENT_ID=replace_with_strava_client_id
STRAVA_CLIENT_SECRET=replace_with_strava_client_secret
STRAVA_ACCESS_TOKEN=replace_with_strava_access_token
STRAVA_REFRESH_TOKEN=replace_with_strava_refresh_token
```
#### Cronometer
Set:
```txt
CRONOMETER_USERNAME=replace_with_cronometer_email
CRONOMETER_PASSWORD=replace_with_cronometer_password
```
Cronometer access can be sensitive because it may involve account credentials. Use a strong unique password and keep `.dev.vars` private.
#### Intervals.icu
Create an API key in Intervals.icu, then set:
```txt
INTERVALS_ICU_API_KEY=replace_with_intervals_icu_api_key
INTERVALS_ICU_ATHLETE_ID=replace_with_intervals_icu_athlete_id
```
### Step 8: Run FitnessMCP Locally
Start the server:
```bash
npm run dev
```
Open:
```txt
http://localhost:8787
```
Check health:
```txt
http://localhost:8787/health
```
The MCP endpoint is:
```txt
http://localhost:8787/mcp
```
### Step 9: Deploy To Cloudflare
Before deploying, add secrets to Cloudflare. Run these one at a time:
```bash
npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET
npx wrangler secret put COOKIE_ENCRYPTION_KEY
```
Then add whichever fitness services you use:
```bash
npx wrangler secret put HEVY_API_KEY
npx wrangler secret put STRAVA_CLIENT_ID
npx wrangler secret put STRAVA_CLIENT_SECRET
npx wrangler secret put STRAVA_ACCESS_TOKEN
npx wrangler secret put STRAVA_REFRESH_TOKEN
npx wrangler secret put CRONOMETER_USERNAME
npx wrangler secret put CRONOMETER_PASSWORD
npx wrangler secret put INTERVALS_ICU_API_KEY
npx wrangler secret put INTERVALS_ICU_ATHLETE_ID
```
Deploy:
```bash
npm run deploy
```
Cloudflare will print your Worker URL. It will look similar to:
```txt
https://fitnessmcp.YOUR_SUBDOMAIN.workers.dev
```
Your production MCP endpoint is:
```txt
https://fitnessmcp.YOUR_SUBDOMAIN.workers.dev/mcp
```
### Step 10: Connect An MCP Client
For an MCP client that supports remote MCP through `mcp-remote`, use:
```json
{
"mcpServers": {
"fitnessmcp": {
"command": "npx",
"args": [
"mcp-remote",
"https://fitnessmcp.YOUR_SUBDOMAIN.workers.dev/mcp"
]
}
}
}
```
Restart your MCP client after saving the config.
## Tool Naming
Tools are namespaced by service:
```txt
fitness_get_connected_services
strava_get_athlete
strava_get_recent_activities
cronometer_get_daily_nutrition
intervals_get_wellness
get_workouts
get_routines
```
The Hevy tools keep their original concise names for compatibility.
## Local Development Commands
```bash
npm run dev
npm run type-check
npm run test:run
npm run lint
npm run format
npm run check
```
## Project Structure
```txt
FitnessMCP/
src/
app.ts # Hono app and route mounting
mcp-agent.ts # MCP server and tool registration
routes/ # MCP and utility routes
middleware/ # bearer auth middleware
lib/
client.ts # Hevy API client
strava-client.ts # Strava API client
cronometer-client.ts # Cronometer API client
intervals-client.ts # Intervals.icu API client
key-storage.ts # encrypted KV credential helpers
service-registry.ts # connected service status
schemas.ts # Zod schemas
transforms.ts # validation and API transforms
test/ # unit and integration tests
wrangler.jsonc # Cloudflare Worker config
.dev.vars.example # local secret template
```
## Production Checklist
Before sharing your Worker URL:
- `wrangler.jsonc` has your own KV namespace IDs
- `.dev.vars` is not committed
- All Cloudflare secrets are set with `wrangler secret put`
- `npm run check` passes
- `/health` returns `status: healthy`
- Your MCP client can call `fitness_get_connected_services`
## Security
Read [SECURITY.md](SECURITY.md) before deploying.
## Contributing
Issues and pull requests are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) first.
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues