Skip to main content
Glama
esowder22

Strava MCP Server

by esowder22

Strava MCP Server

A small, read-only Model Context Protocol server that gives Claude live access to your personal Strava data — activities, splits, heart-rate/pace streams, zones, and lifetime totals — so it can coach off your real training instead of manual exports.

Runs in Strava "single-player mode": it only ever connects your own account.

What it exposes

All tools are reads. The server never creates, edits, or deletes anything on Strava.

Tool

What it returns

get_athlete

Your profile (name, location, weight, FTP if set)

get_stats

Lifetime, YTD, and last-4-weeks totals per sport

list_activities

Recent activities, paginated, with optional date filters

get_activity

Full detail for one activity (splits, pace, HR, power, elevation)

get_activity_streams

Time-series streams for detailed analysis

get_athlete_zones

Configured heart-rate and power zones

Related MCP server: Strava MCP Server

Prerequisites

  • Python 3.10+

  • A Strava account with an active subscription (required to create an API app)

Setup

1. Create a Strava API application

  1. Go to https://www.strava.com/settings/api.

  2. Create an app. Set Authorization Callback Domain to localhost.

  3. Note your Client ID and Client Secret (keep the secret private).

2. Install

git clone <your-repo-url> strava-mcp-server
cd strava-mcp-server
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

3. Configure credentials

cp .env.example .env
# edit .env: set STRAVA_CLIENT_ID and STRAVA_CLIENT_SECRET

4. Authorize (one time) to get a refresh token

python scripts/get_token.py

This opens your browser, catches the redirect on localhost, exchanges the code, and prints a STRAVA_REFRESH_TOKEN=... line. Paste it into .env.

5. Register the server with Claude

Claude Code — copy mcp.example.json to .mcp.json in the repo root (adjust the python path to your venv, e.g. .venv/bin/python, if needed), then start Claude Code from this directory. Approve the server when prompted.

Claude Desktop — add the strava block from mcp.example.json to your claude_desktop_config.json under mcpServers, using absolute paths:

{
  "mcpServers": {
    "strava": {
      "command": "/absolute/path/to/strava-mcp-server/.venv/bin/python",
      "args": ["-m", "strava_mcp.server"],
      "cwd": "/absolute/path/to/strava-mcp-server"
    }
  }
}

Restart Claude Desktop. You should see the Strava tools appear.

6. Sanity check

python -m strava_mcp.server   # should start and wait on stdio; Ctrl-C to exit

Security model

  • No secrets in git. .env, .strava_tokens.json, and key files are gitignored. Only .env.example is tracked.

  • Read-only scope. The app requests read, activity:read_all, and profile:read_all — no write scopes. The server issues only GET requests to data endpoints.

  • Token hygiene. Access tokens (6-hour lifetime) are refreshed automatically from your refresh token. Strava rotates the refresh token on each exchange; the server persists the current one to .strava_tokens.json (chmod 600, gitignored).

  • Rate limits. Honors Strava's 200 req / 15 min and 2,000 / day limits with automatic backoff on HTTP 429.

  • Revoking access. Remove the app anytime at https://www.strava.com/settings/apps. Delete .strava_tokens.json and .env to purge local credentials.

Publish to GitHub

From the repo root (secrets are already gitignored, so this is safe):

The GitHub repo already exists at https://github.com/esowder22/strava-mcp-server, so just wire up the remote and push:

git init
git add .
git status                     # confirm .env / .strava_tokens.json are NOT listed
git commit -m "Initial commit: read-only Strava MCP server"
git branch -M main
git remote add origin git@github.com:esowder22/strava-mcp-server.git
git push -u origin main

Prefer HTTPS over SSH? Use git remote add origin https://github.com/esowder22/strava-mcp-server.git instead.

If the GitHub repo was created with a README/license and the push is rejected, run git pull --rebase origin main once, then push again. Keep the repo private — even though no secrets are committed, there's no reason to make it public.

Compatibility note

Written for the current mcp 2.x SDK (where FastMCP is MCPServer), with a fallback import so it also runs on mcp 1.x. No code change needed either way.

License

MIT — see LICENSE.

Available Tools

6 tools
get_activityB

Return full detail for one activity (splits, pace, HR, power, elevation, segments).

ParametersJSON Schema
NameRequiredDescriptionDefault
activity_idYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the burden of behavioral disclosure. It communicates that this is a read operation ('Return') and lists the content categories included, which is useful. It does not address edge cases, error behavior, authentication needs, or whether any data is modified, though these are less critical for a simple getter.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single front-loaded sentence with no filler. It states the primary action and then packs the return scope into a compact parenthetical list. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With one parameter, no output schema, and no annotations, this simple tool is mostly well described: the purpose and return categories are clear. It lacks guidance on where activity_id comes from and any output shape details, but for a low-complexity getter the description is nearly sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the single parameter activity_id is only documented in the schema as an integer. The description adds minimal semantic value by saying 'one activity', implying the ID identifies the target activity. It does not explain how to obtain the ID, format expectations, or any relationship to list_activities.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with a specific verb and resource: 'Return full detail for one activity'. The parenthetical enumerates concrete fields (splits, pace, HR, power, elevation, segments), which clarifies what 'full detail' means. However, it does not explicitly contrast with sibling tools like list_activities or get_activity_streams, so differentiation is implicit rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: call this when you need complete detail for a single activity identified by an activity_id. It does not provide explicit when-to-use versus alternatives, such as telling users to prefer list_activities for summaries or get_activity_streams for raw stream data. No exclusions or alternative routing are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_activity_streamsA

Return time-series streams for an activity for detailed pace/HR/elevation analysis.

Args: activity_id: The activity to inspect. keys: Stream types to fetch. Defaults to time, distance, heartrate, velocity_smooth, altitude.

ParametersJSON Schema
NameRequiredDescriptionDefault
keysNo
activity_idYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of behavioral disclosure. It states that streams are returned and documents the default stream keys when keys is null, but it does not discuss units, missing stream behavior, pagination, or side effects beyond the implied read-only nature of 'Return.'

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded, with a clear one-line purpose statement followed by a succinct parameter list. No filler or redundant restatement of the schema appears.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a low-complexity read tool with no output schema and no annotations, the description covers the required parameter, optional key selection, defaults, and return concept. It does not specify response shape or units, but the essential invocation information is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It fully explains both parameters: activity_id is 'the activity to inspect,' and keys lists the stream types to fetch with a concrete default set. This is exactly the semantic information an agent needs beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Return time-series streams for an activity.' It further narrows the purpose with 'for detailed pace/HR/elevation analysis,' which clearly distinguishes it from siblings like get_activity, get_stats, and list_activities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'for detailed pace/HR/elevation analysis' implies when to use the tool, but the description does not explicitly say when to prefer it over get_activity or get_stats, nor does it mention exclusions or alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_athleteA

Return the authenticated athlete's profile (name, location, weight, FTP if set).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the behavioral disclosure burden. It signals read-only behavior ('Return'), clarifies the authentication context ('authenticated athlete'), and even discloses the conditional nature of FTP ('if set'). This is solid for a simple getter, though it does not discuss error cases or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence with no filler. The action, target, and returned fields are front-loaded, and the conditional FTP detail is efficiently parenthesized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with no output schema, the description is complete: it identifies the exact resource and lists the returned fields. There is nothing an agent needs to know in order to invoke this tool correctly that is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there are no parameter semantics for the description to clarify. Per the rubric this earns a baseline 4; the description instead usefully documents the output fields, which is the relevant information for an agent.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with a specific verb ('Return') and a concrete resource ('the authenticated athlete's profile'), then enumerates the contained fields. This clearly distinguishes it from sibling tools like get_activity, get_stats, and get_athlete_zones, all of which target different data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes clear it is the tool for retrieving the current athlete's profile data, and the sibling names show that other tools serve different purposes. It does not explicitly state 'use this when...' or name alternatives, but the context is obvious enough for a zero-parameter profile fetch.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_athlete_zonesA

Return the athlete's configured heart-rate and power zones.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are absent, so the description carries the full burden. It does state the tool 'returns' data, implying a read-only operation, but adds no further context on authentication, rate limits, or error behavior. For a simple no-parameter read, this is minimally adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no wasted words: it names the verb, resource, and the two zone types. It is perfectly sized for a tool with no parameters and a simple purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read tool with no output schema, the description states exactly what is returned (heart-rate and power zones). It doesn’t mention units or response structure, but given the simplicity of the call, little more is strictly necessary.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and schema coverage is 100% with an empty properties object. There is nothing to document, so the description carries no additional parameter burden – baseline 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the specific verb 'Return', the resource ('the athlete's configured heart-rate and power zones'), and scopes it to zones, which distinguishes it from siblings like get_athlete and get_activity. Even without seeing the schema, an agent can tell this is the zones-fetching endpoint.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to call this tool versus alternatives like get_athlete or get_stats. There’s no mention of prerequisites, contextual triggers, or exclusions – the agent must infer that this is for zones specifically.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_statsA

Return lifetime, year-to-date, and recent (last 4 weeks) totals for the athlete.

Covers run, ride, and swim distance/time/elevation. Useful for tracking load and progress over time.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the behavioral disclosure burden. It explains the returned aggregation windows and the specific metrics, which is sufficient for a read-only, zero-parameter stats endpoint. It does not discuss response structure or auth, but nothing about the tool suggests hidden side effects or surprising behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded, with the core behavior stated in the first sentence. The second sentence adds useful scope and use-case context without redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters, no annotations, and no output schema, the description adequately conveys what the tool returns and in what time buckets. It could be slightly more complete by noting units or response format, but for a simple aggregate-stats tool it provides enough context for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline is 4. There are no parameter semantics to clarify, and the description does not mistakenly imply parameters exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Return') and identifies the resource ('totals for the athlete') with clear time scopes (lifetime, year-to-date, last 4 weeks). It clearly distinguishes the tool from siblings like get_activity or list_activities by emphasizing aggregated statistics rather than individual records.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: 'tracking load and progress over time.' It also enumerates the covered sports and metrics, which helps an agent decide when this tool is appropriate. However, it does not explicitly state when to prefer sibling tools or when not to use this one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_activitiesA

List the athlete's activities, most recent first.

Args: per_page: Activities per page (1-200, default 30). page: Page number (default 1). before: Optional Unix timestamp; only activities before this time. after: Optional Unix timestamp; only activities after this time.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
afterNo
beforeNo
per_pageNo

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the behavioral burden, and it does add ordering and pagination behavior. However, it never explicitly says the operation is read-only, and it does not describe the return shape (e.g., summaries vs. full activity objects), which are meaningful gaps for an unannotated tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and well-structured: a single purpose sentence followed by a compact argument list. Every line provides useful information, and the primary purpose is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a four-parameter tool with no output schema and no annotations, the description covers the main call surface well. However, it leaves the response payload type ambiguous—what fields or summary level are returned—and says nothing about authentication or error conditions, so an agent cannot fully predict downstream behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description compensates fully: it defines page and per_page with defaults and range, and crucially explains before and after as optional Unix timestamps filtering activities by time. Every parameter gains semantic meaning beyond the raw JSON schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource—'List the athlete's activities'—and states the ordering ('most recent first'). This clearly distinguishes it from singular-fetch siblings like get_activity and from data-detail tools such as get_activity_streams.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The applicable context is clear: this is the bulk listing/paging tool for an athlete's activities, with time-range filters for narrowing the window. It does not explicitly name alternatives or state when not to use it, so it stops short of a perfect 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedget_activity
    • First observedget_activity_streams
    • First observedget_athlete
    • First observedget_athlete_zones
    • First observedget_stats
    • First observedlist_activities

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a clearly distinct resource or granularity: athlete profile, aggregate stats, activity list, activity detail, time-series streams, and zones. The only close pair, get_activity and get_activity_streams, is cleanly separated by summary detail vs. raw time-series data.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern, with five using get_ and one using list_activities. The lone list_ is still a standard retrieval verb, so the naming stays predictable and coherent.

Tool Count5/5

Six tools is a well-scoped size for a read-only Strava analytics server. Each tool covers a distinct part of the activity/athlete data surface without unnecessary duplication or bloat.

Completeness5/5

For the apparent purpose of retrieving athlete and activity data, the surface is complete: profile, aggregate stats, activity listing, detailed activity, streams, and zones. There are no dead ends for common queries like 'how fast was my last ride?' or 'what are my power zones?'

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers