Strava MCP Server
The Strava MCP Server provides programmatic access to your Strava account to manage, analyze, and automate fitness data through tools, resources, and AI prompts.
Activities
List activities with date range filtering and pagination
Get detailed info (splits, laps, segment efforts, gear, calories)
Create manual entries and update properties (name, type, gear, description, visibility)
List comments, kudoers, laps, and heart rate/power zone distributions
Athletes
Get your authenticated athlete profile (name, location, bikes, shoes)
Retrieve heart rate and power zones
Get recent, year-to-date, and all-time stats for runs, rides, and swims
Segments
Get detailed segment info (distance, elevation, grade, effort count)
List and filter efforts by date range; get specific efforts with achievements
Explore popular segments within a geographic bounding box
Star/unstar segments and list your starred segments
Routes
List, view detailed route info, and export routes as GPX or TCX files
Streams (Time-Series Data)
Access high-resolution data streams for activities, segment efforts, segments, and routes (heart rate, power, cadence, altitude, GPS, speed, etc.)
Clubs
List clubs you belong to, get club details, and list recent activities, members, and admins
Gear
Get equipment details for bikes and shoes (brand, model, total distance)
Uploads
Upload FIT, TCX, or GPX files to create new activities and check processing status
AI Prompts & Resources
Use built-in prompts for weekly training summaries, single activity analysis, training plan reviews, segment comparisons, and race readiness assessments
Access read-only athlete profiles, stats, activity details, segment info, and route GPX exports as context resources
Supports OAuth with automatic token refresh
Provides tools for interacting with the Strava API v3, allowing for the management of activities, athlete profiles, segments, routes, clubs, and gear, as well as the ability to upload activity files.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Strava MCP Server show my running stats for this year"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
strava-mcp
Ask an AI assistant anything about your Strava history, answered in milliseconds from a complete local mirror of your account.
strava-mcp is a self-hosted MCP server for one athlete's own Strava data. A background sync copies everything Strava's API returns for the account into a single DuckDB file, within Strava's rate limits; the tools answer from that file, and a read-only snapshot of it feeds Grafana, notebooks and backups. One container, one docker compose up -d.
A complete mirror. Activities with laps, splits, best efforts and every segment effort; full-resolution streams; zones; kudos, comments, photos; gear, segments, routes, clubs, the profile and a history of its totals. Stored verbatim, versioned when it changes, projected into typed tables with a description on every column.
Rate-limit aware sync. Usage comes from Strava's headers; background work takes at most 75% of each window and spreads it over the day, so your questions always have budget. A webhook delivers new activities in seconds.
Cache-first tools, plus SQL. 33 tools include local-only SQL/schema/status, cache-first reads and explicit Strava writes (upload status always reads Strava).
strava_queryuses engine-enforced read-only transactions over stored history; check coverage before treating it as complete. Mirrored answers preserve provenance.Discoverable context without hidden sync.
strava://reference/usagelists URI templates and the five local-only analysis prompts, with bounded examples and costs, even in clients that hide template discovery. Local schema, coverage/status and budget resources cost zero API calls; missing rate headers mean unknown accounting, not free requests.A snapshot anything can read. A consistent read-only copy, published next to the mirror and optionally over HTTP. Grafana, a marimo notebook and scheduled backups ship as Compose profiles.
Bearer token or your identity provider. A bearer protects the endpoint by default; the
oauthprofile adds an OAuth 2.1 gateway for claude.ai, Claude Code, Cursor and any client that signs in with your OIDC provider.
flowchart LR
strava[Strava API v3]
subgraph server [strava-mcp container]
direction TB
limiter[rate limiter] --> queue[durable job queue] --> engine[sync engine]
engine --> mirror[(DuckDB mirror)]
mirror --> tools[MCP tools, resources, prompts]
mirror -- periodic copy --> snapshot[(read-only snapshot)]
end
strava <-->|REST, webhook| limiter
tools -->|Streamable HTTP, bearer or OAuth| client[Claude, Cursor, Codex, pi, ...]
snapshot --> grafana[Grafana]
snapshot --> marimo[marimo notebook]
snapshot --> backup[backups]Quickstart
With Docker Compose (v2.24 or later), after creating a Strava API application with localhost as its Authorization Callback Domain:
git clone https://github.com/justmytwospence/strava-mcp.git && cd strava-mcp
cp .env.example .env # set STRAVA_CLIENT_ID, STRAVA_CLIENT_SECRET, MCP_BEARER_TOKEN
docker compose run --rm -p 8765:8765 strava-mcp auth # authorize once in the browser
docker compose up -d # http://<host>:8000/mcpThen connect a client, pasting the MCP_BEARER_TOKEN from .env (or source .env first):
claude mcp add --transport http strava http://localhost:8000/mcp --header "Authorization: Bearer $MCP_BEARER_TOKEN"Without Docker, the npm package runs the same server over stdio for a client that spawns it (Claude Desktop, Codex, pi, ...), with the mirror in ./state/:
STRAVA_CLIENT_ID=12345 STRAVA_CLIENT_SECRET=... npx -y --package @justmytwospence/strava-mcp strava-mcp-auth
npx -y @justmytwospence/strava-mcpThe quickstart walks through the Strava application, the first sync and what it costs; clients covers Claude Code, Claude Desktop, claude.ai, Cursor, VS Code, Codex, ChatGPT, Gemini CLI and pi.
Related MCP server: fitness-mcp-server
Things you can ask
"How did my weekly running volume change over the last three months?"
"Compare all my efforts on segment 1234: is the improvement pace or heart rate?"
"What was my heart-rate drift in yesterday's long run?"
"List every ride over 100 km with more than 2,000 m of climbing."
"Which bike has the most kilometres this year?"
"Rename this morning's ride to 'Coffee ride' and mark it as a commute."
Most of these are one SQL query over the typed tables rather than dozens of API calls.
Documentation
justmytwospence.github.io/strava-mcp: quickstart, clients, FAQ, configuration, authentication, how sync works, the mirror and the snapshot, Grafana, notebooks, backups, operations, troubleshooting, tools reference, schema, export API.
Works well with garmin-mcp
garmin-mcp is the sibling project for Garmin Connect: the same design over sleep, HRV, Body Battery, training status and the original FIT files. Its optional Strava sync reads this server's export endpoint to rename Garmin activities after Strava and to remove courses for routes you have unstarred, without spending Strava API quota.
Strava's terms
Strava's API Agreement and API Policy restrict caching Strava data beyond seven days, storing it in persistent databases, and operating MCP servers or similar agent interfaces over the API; Strava's own MCP connector is the one it authorizes. This project mirrors a single athlete's own data onto that athlete's own hardware. Read the terms and the brand guidelines and decide for yourself. Not affiliated with or endorsed by Strava.
Contributing
See CONTRIBUTING.md for the layout, the checks (pnpm run lint, pnpm run typecheck, pnpm test), how to add a column or a table, and how releases are made.
License
PolyForm Noncommercial 1.0.0: free for personal use, research, education and noncommercial organizations. Commercial use requires a separate license; contact Spencer Boucher. Versions released before 2026-10-27 under MIT remain available under MIT.
Outside contributions require agreeing to a contributor license agreement; open an issue before sending a pull request.
Available Tools
33 toolsstrava_create_activityCreate ActivityA
Create a manual activity entry (one API request). Requires activity:write scope and intent. Do not blindly retry a lost response; duplicate creation is possible.
Inputs: name (required), sport_type (required), elapsed_time (required), start_date_local (required), +4 more.
strava_create_uploadUpload Activity FileA
Upload an activity file (FIT, TCX, GPX) to create a new activity (one API request plus later status polls). Requires activity:write. Maximum decoded file size 25 MiB; canonical base64 only. Do not replay a lost response; reconcile first. Returns an upload ID for strava_get_upload.
Inputs: data_type (required), file_content (required), name, commute, +3 more.
strava_export_route_gpxExport Route as GPXARead-onlyIdempotent
Export a route as a GPX file. Returns raw GPX XML content.
Inputs: route_id (required).
strava_export_route_tcxExport Route as TCXARead-onlyIdempotent
Export a route as a TCX file. Returns raw TCX XML content.
Inputs: route_id (required).
strava_export_segment_gpxExport Segment as GPXARead-onlyIdempotent
Export a Strava segment as a GPX file for navigation. Returns GPX XML that can be imported into Garmin Connect, Coros, or other GPS devices. Note: The Strava API does not support uploading routes, so the GPX must be imported manually into your device/app.
Inputs: segment_id (required).
strava_get_activityGet ActivityARead-onlyIdempotent
Get detailed information about a specific activity including description, calories, splits, laps, segment efforts, best efforts, and gear. Served from the local mirror; recent activities are refreshed from Strava.
Inputs: activity_id (required), include_all_efforts.
strava_get_activity_streamsGet Activity StreamsARead-onlyIdempotent
Get high-resolution time-series data for an activity (heart rate, power, cadence, altitude, GPS coordinates, etc.). Data is downsampled if too large. Cache miss normally costs one API request. Missing stream rate headers mean unknown accounting, not free calls; check strava_sync_status or strava://mirror/budget first.
Inputs: keys (required), activity_id (required), max_points.
strava_get_athlete_statsGet Athlete StatsARead-onlyIdempotent
Get activity statistics for the authenticated athlete: recent, year-to-date, and all-time totals for runs, rides, and swims. Includes biggest ride distance and biggest climb.
Inputs: athlete_id.
strava_get_athlete_zonesGet Athlete ZonesBRead-onlyIdempotent
Get the authenticated athlete's heart rate and power zones.
Inputs: no named parameters.
strava_get_authenticated_athleteGet Authenticated AthleteARead-onlyIdempotent
Get the profile of the currently authenticated athlete, including name, location, stats summary, bikes, and shoes.
Inputs: no named parameters.
strava_get_clubGet ClubARead-onlyIdempotent
Get detailed information about a club including description, member count, and sport type.
Inputs: club_id (required).
strava_get_gearGet GearARead-onlyIdempotent
Get equipment details by ID (name, brand, model, total distance). Gear IDs look like "b12345" for bikes or "g12345" for shoes.
Inputs: gear_id (required).
strava_get_routeGet RouteBRead-onlyIdempotent
Get detailed route information including distance, elevation gain, and estimated moving time.
Inputs: route_id (required).
strava_get_route_streamsGet Route StreamsARead-onlyIdempotent
Get bounded/downsampled GPS, distance and altitude data for a route. A cache refresh normally costs one API request; check strava_sync_status or strava://mirror/budget first.
Inputs: route_id (required), max_points.
strava_get_segmentGet SegmentBRead-onlyIdempotent
Get detailed information about a segment including distance, elevation, grade, effort count, and athlete count.
Inputs: segment_id (required).
strava_get_segment_effortGet Segment EffortBRead-onlyIdempotent
Get a specific segment effort by ID, including elapsed time, heart rate, watts, and achievements.
Inputs: effort_id (required).
strava_get_segment_effort_streamsGet Segment Effort StreamsARead-onlyIdempotent
Get bounded/downsampled time-series data for a segment effort. Cache miss normally costs one API request; check strava_sync_status or strava://mirror/budget. Missing headers do not exempt requests from known quotas.
Inputs: keys (required), effort_id (required), max_points.
strava_get_segment_streamsGet Segment StreamsARead-onlyIdempotent
Get bounded/downsampled GPS, distance and altitude data for a segment. Cache miss normally costs one API request; check strava_sync_status or strava://mirror/budget first.
Inputs: keys (required), segment_id (required), max_points.
strava_get_uploadGet Upload StatusARead-onlyIdempotent
Read upload processing status directly from Strava (one API request per call, never mirrored). Returns status, error and the resulting activity ID. Poll sparingly; check strava_sync_status or strava://mirror/budget and respect cooldown.
Inputs: upload_id (required).
strava_list_activitiesList Athlete ActivitiesARead-onlyIdempotent
List the authenticated athlete's activities, newest first. Supports filtering by date range and pagination. Served from stored history, which can be incomplete during backfill. A stale listing refresh traverses upstream pages; local page size does not cap API requests. Check strava_sync_status or strava://mirror/budget before broad refreshes; narrow dates/use local SQL first.
Inputs: page, after, before, per_page.
strava_list_activity_commentsList Activity CommentsARead-onlyIdempotent
Page through stored comments. A cache refresh fetches the entire upstream list, potentially many API pages regardless of per_page.
Inputs: activity_id (required), page, per_page.
strava_list_activity_kudoersList Activity KudoersARead-onlyIdempotent
Page through stored kudoers. A cache refresh fetches the entire upstream list, potentially many API pages regardless of per_page.
Inputs: activity_id (required), page, per_page.
strava_list_activity_lapsList Activity LapsARead-onlyIdempotent
List laps of an activity. Each lap includes distance, time, speed, heart rate, watts, and elevation.
Inputs: activity_id (required).
strava_list_activity_zonesList Activity ZonesARead-onlyIdempotent
Get heart rate and power zone distribution for an activity. Shows time spent in each zone.
Inputs: activity_id (required).
strava_list_athlete_clubsList Athlete ClubsARead-onlyIdempotent
Page through stored clubs the athlete belongs to. Refresh fetches all upstream pages; local per_page does not cap API request cost.
Inputs: page, per_page.
strava_list_athlete_routesList Athlete RoutesBRead-onlyIdempotent
Page through stored routes. Refresh fetches all upstream pages; local per_page does not cap API request cost.
Inputs: page, per_page, athlete_id.
strava_list_segment_effortsList Segment EffortsARead-onlyIdempotent
List the authenticated athlete's efforts on a segment, newest first, optionally filtered by date range. Limited to per_page results (no next-page cursor). Mirror history can be incomplete; fallback fetches all upstream pages before slicing, so per_page does not cap API calls. Check strava_sync_status or strava://mirror/budget; prefer stored SQL when budget is tight.
Inputs: segment_id (required), per_page, end_date_local, start_date_local.
strava_list_starred_segmentsList Starred SegmentsARead-onlyIdempotent
Page through stored starred segments. A stale refresh fetches the complete upstream list (multiple API pages); local per_page does not cap request cost.
Inputs: page, per_page.
strava_queryQuery the Strava Mirror (SQL)ARead-onlyIdempotent
Run a read-only DuckDB SQL query against the athlete's stored Strava data (possibly incomplete; check sync status). Enforced read-only transaction, 30 seconds, 5000 rows maximum; no file/network access. Use strava_schema first to see the tables. Main tables: activity, activity_stream_point (per-point streams: time, distance, lat, lng, altitude, heartrate, cadence, watts, temp, velocity_smooth, grade_smooth), activity_lap, activity_split, activity_best_effort, activity_segment_effort, segment, activity_zone_bucket, gear, route, athlete_stats. Units: meters, seconds, m/s. raw_current holds every payload as JSON (column body) for fields not in a typed table. Costs no Strava API calls.
Inputs: sql (required), max_rows. Returns: note, rows, columns, row_count, +1 more
strava_schemaDescribe the Strava MirrorARead-onlyIdempotent
List the mirror's tables and views with their descriptions and row counts, or, given a table name, its columns with types, units and descriptions. Use before strava_query.
Inputs: table. Returns: table, tables, columns, comment
strava_star_segmentStar/Unstar SegmentADestructiveIdempotent
Star or unstar a segment for the authenticated athlete (one write API request). Unstarring removes an existing preference. Reconcile a lost response before retrying.
Inputs: starred (required), segment_id (required).
strava_sync_statusStrava Mirror Sync StatusARead-onlyIdempotent
How complete and fresh the local mirror is: activity coverage (details, streams, zones), the sync queue by kind, last run of each periodic task, recent errors, and unmapped fields. Zero API calls. Rate status distinguishes header observations from local estimates and unknown pools; missing headers never mean free calls. Check this or strava://mirror/budget before broad remote reads; 429 cooldown/reset times apply to all priorities.
Inputs: no named parameters.
strava_update_activityUpdate ActivityADestructiveIdempotent
Update an activity's mutable properties. Requires activity:write scope. Only provided fields are updated (one API request); replacing values can destroy prior content. Reconcile lost responses before retrying.
Inputs: activity_id (required), name, commute, gear_id, +4 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 33 tools
Most tools map cleanly to a distinct Strava resource plus action, and the stream/list variants are scoped by entity. The main conceptual overlap is between local mirror listing tools and the generic SQL query/schema tools, but the descriptions make the distinction fairly clear.
Nearly all tools use a consistent strava_ snake_case prefix and verb_noun pattern, such as strava_list_activities and strava_create_upload. Minor deviations like strava_schema, strava_query, and strava_sync_status are still readable and predictable.
With 33 tools, the surface is large enough to feel heavy and increases selection burden. The broad Strava domain justifies many endpoints, but several stream, export, and local-mirror operations could potentially be consolidated.
The server covers core Strava workflows well: activities, segments, efforts, routes, streams, clubs, gear, uploads, athlete stats, and SQL mirror access. Some gaps remain, such as club activities/members and a few mutation endpoints, though some may reflect Strava API limitations.
Maintenance
Related MCP Connectors
Strava MCP tools for AI: athletes, activities, segments, clubs, routes. Powered by HAPI MCP server.
Adaptive running coach MCP server — training data, plans, and recovery for AI assistants.
Pace is a remote MCP server that exposes wearable and fitness data to Claude via the Model Context Protocol. It connects to Garmin, Oura, Whoop, Polar, Fitbit and 20+ devices and provides 15 tools for querying sleep, activity, recovery, and training data. Hosted on Google Cloud Run, OAuth 2.1 authentication, Streamable HTTP transport. Instructions: First you need to create an account at: https://pacetraining.co and connect your wearables. After that you can connect the remote Server via Custom Connector in Claude and OAuth 2.1 Flow startet.
Remote MCP server for training, nutrition, wellness, and performance data with OAuth 2.0.
Related MCP Servers
- AlicenseBqualityDmaintenanceA Model Context Protocol server that enables users to access Strava fitness data, including user activities, activity details, segments, and leaderboards through a structured API interface.34MIT
- FlicenseNot gradedqualityDmaintenanceProvides MCP servers for Claude to access fitness data from Strava and intervals.icu, enabling natural language queries for activity analysis, advanced training metrics, and wellness tracking.1-
- AlicenseNot gradedqualityCmaintenanceMCP server for Strava integration, enabling LLMs to query activities, athlete stats, segments, routes, and perform training analysis.9MIT
- FlicenseNot gradedqualityDmaintenanceMCP server to fetch Strava activities using OAuth authentication with automatic token refresh. Allows retrieving recent activities, activities by date range, activity details, and athlete stats.-