Reported issues for strava-mcp
Pod holds 24 of 145 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.
Back to strava-mcp.
Most discussed
spike: external tile fetch through host CSP and free tile-source choice
Summary
Determine whether an MCP App can fetch external map tiles through the host's sandbox/CSP, and choose the free tile source to standardize on.
Area
mcp-app
Motivation
MCP App iframes block external connections by default. The server can declare _meta.ui.csp (connectDomains / resourceDomains), but the host (Claude) must honor those allowlisted origins through its double-iframe sandbox. This is the gating unknown for any basemap. We also need to pick between OpenFreeMap's pu
Read the thread · 2026-06-08 · closed · 2 comments
feat: add Strava webhook (push subscription) support for real-time activity events
Problem
The server can only poll. Strava's Webhook Events API can push create / update / delete events for activities and athlete deauthorizations, enabling real-time reactions (cache invalidation, notifications) without polling and reducing rate-limit pressure.
Current behaviour
No subscription handling exists: no /push_subscriptions calls in apps/server/src/stravaClient.ts, and no webhook callback route in apps/server/src/index.ts.
Proposed approach
- Add a public callback
Read the thread · 2026-06-07 · closed · 2 comments
epic: Training analysis — prediction, splits, taper, and the fitness chart
Tracking issue. Four features over the same analysis primitives.
Why these belong together
They share fitnessTrend.ts, hillAnalysis.ts's grade-adjusted pace, and the getBestEfforts scan pattern. One of the pairs is explicit: #267's body already points at the companion view issue.
Ordered batches
1. Companion pair — order matters
- #267 — extend
get-fitness-trendwith a planned-load taper projection (keep all math infitnessTrend.ts) - #262 —
view-fitness-trendMCP App c
Read the thread · 2026-07-26 · closed · 1 comment
epic: Collapse the duplicated formatters
Tracking issue. Two issues filed as explicit companions — the same class of drift on either side of the server/app boundary.
Why these belong together
Each body names the other. They are the same inventory exercise done twice, and the inventory is the expensive part.
Members — either order
- #252 — hoist
formatClock, the short-date helper, and oneformatDurationShortinto@strava-mcp/data, then delete the per-app copies. MCP App packages cannot import each other, so `packages/dat
Read the thread · 2026-07-26 · closed · 1 comment
epic: MCP protocol surface — schemas, capabilities, end-to-end coverage
Tracking issue. Groups everything the server advertises to a host — input schemas, output schemas, capabilities, notifications — plus the one test that would catch a break in any of them.
Why these belong together
31 of 46 tools return text only, no capability beyond tools/resources/prompts is advertised, and the protocol layer is only partly tested — tools/list is exercised end-to-end but nothing else is. These issues share server.ts's registration surface, tools/outputs.ts, an
Read the thread · 2026-07-26 · closed · 1 comment
chore: collapse the server formatDuration duplicates and the utils.ts split
Context
get-activity-zones formats durations differently from every other tool because four formatDuration variants coexist server-side, one of them commented out with stale breadcrumbs. Nothing catches this class of drift: knip cannot see commented code or a genuinely-imported duplicate. A companion issue covers the same problem across the app packages (formatters into packages/data).
Evidence
- Canonical null-safe version:
apps/server/src/formatters.ts:6(3725renders1:02:05
Read the thread · 2026-07-25 · closed · 1 comment
refactor: move duplicated clock, date, and duration formatters into @strava-mcp/data
Context
Formatting helpers have drifted into per-app copies with incompatible output. formatClock is implemented twice; a MONTHS array plus UTC short-date helper is duplicated byte-for-byte in two a11y modules with a third near-copy; short durations render three different ways for the same idea (1h 05m, 1h5m, hours). MCP App packages cannot import each other, so packages/data is the only shared home. Issue #216 fixed a pace-rollover bug in one copy only, which is the failure mode th
Read the thread · 2026-07-25 · closed · 1 comment
Reposition strava-mcp as a supplement to the official Strava MCP connector
Summary
Strava has shipped an official MCP connector. It overlaps with our read-only tools but covers only a slice of what this server does. This epic repositions strava-mcp as a supplement to the official connector: we drop the duplicate reads and keep everything the official MCP cannot do.
Docs:
- FAQ: https://support.strava.com/en-us/articles/15401526-strava-api-and-mcp-faq
- Connector: https://support.strava.com/en-us/articles/15401531-strava-mcp-connector
Official connector pro
Read the thread · 2026-06-22 · closed · 1 comment
Most recent
epic: Release and container plumbing — gates that gate, manifests that match
Tracking issue. Groups five open issues across the release pipeline: what gates a merge, what builds the image, and what the registry is told afterwards.
Why these belong together
Four of the five edit .github/workflows/, scripts/setup-branch-protection.sh, or the release manifests, and three of them are the same failure in different places — a step that was designed to gate something and does not.
- #358:
docker.ymlengineers itschangesjob specifically so a required Docker statu
Read the thread · 2026-08-23 · open · 0 comments
epic: Tool surface consistency — arg names, error handling, output honesty
Tracking issue. Groups four open issues that all rewrite the same tool handler bodies in apps/server/src/tools/.
Why these belong together
The overlap is literal, not thematic. Seven of the eleven tools #354 migrates destructure an id argument that #352 renames:
| Tool | Today | #354 rewrites | #352 renames |
|---|---|---|---|
getSegment.ts |
execute: async ({ segmentId } |
catch block :75-88 | segmentId → segment_id |
getActivityLaps.ts |
execute: async ({ id } |
Read the thread · 2026-08-23 · open · 0 comments
epic: Request path round two — coalescing, immutability, cached token reads
Tracking issue. Groups three open issues that all finish the same story: one read path that caches instead of re-fetching.
Why these belong together
#355 and #357 rewrite the same five lines. fetchClient.ts:462-466 is the cache-lookup block, ending in return { data: cached as T } — #355 wraps that site in an in-flight promise map so concurrent identical GETs share one upstream call, #357 changes what that same return hands back so a consumer cannot mutate the cached object. Landed sep
Read the thread · 2026-08-23 · open · 0 comments
perf: stop get-activity-photos and get-activity-zones dumping raw JSON into text content
Summary
get-activity-photos and get-activity-zones append a pretty-printed dump of the entire raw Strava response to their text content, then also return the same data as structuredContent. Every successful call pays for both copies, and the raw one is the larger of the two.
Area
server
Motivation
structuredContent + outputSchema is the architecture invariant for tools returning data: the machine-readable copy is the structured payload, the text copy is for a human reading th
Read the thread · 2026-08-23 · open · 0 comments
chore: resolve the stale image identifier committed in server.json
Summary
Committed server.json reads "version": "2.13.2" but packages[0].identifier is still ghcr.io/ljcl/strava-mcp:2.3.0 — release-please only updates $.version, and the real tag is stamped transiently by publish-mcp.yml at publish time, so the committed file drifts ten minor versions behind.
Area
ci-release
Motivation
Anyone reading the repo (or copying the registry reference out of server.json) sees a long-stale image tag. It also makes release-PR diffs misleading — th
Read the thread · 2026-08-22 · open · 0 comments
feat: add a race-prep prompt chaining prediction and taper solving
Summary
prompts.ts ships three prompts (weekly-review, annotate-last-run, segment-hunt). The toolset's most distinctive capability — answering "am I on form for my goal race?" via get-race-prediction plus get-fitness-trend's solved taper — has no guided prompt packaging the sequence.
Area
server
Motivation
Prompts are the discoverability layer for multi-step workflows in Claude Desktop/Code hosts. The race-prep sequence needs real ordering (best efforts → Riegel prediction → fitn
Read the thread · 2026-08-22 · open · 0 comments
docs: correct get-activity-photos' output prose and drop the Output Format sections
Summary
get-activity-photos and get-activity-zones are the only two tools whose descriptions carry an Output Format: section, and both advertise a "complete raw JSON" text dump — get-activity-photos enumerating fields (Source, uploaded_at, "URLs for different sizes") that reach the text branch but are absent from its structuredContent. Their prose is also the wordiest on the surface: get-activity-photos spends 26 lines where comparable tools spend a paragraph.
Area
server
Mo
Read the thread · 2026-08-22 · open · 0 comments
chore: serve /health token status from the in-memory token cache
Summary
getTokenStatus() calls loadTokens() directly instead of reading the in-memory cachedTokens that getStravaToken maintains, so every authed /health or /auth/status poll pays a filesystem read and re-emits the "[TokenManager] Loaded tokens …" stderr line.
Area
server
Motivation
/health backs the Docker HEALTHCHECK and operator dashboards, i.e. it is polled continuously — each poll currently costs a disk read plus log noise that buries real telemetry lines in `doc
Read the thread · 2026-08-22 · open · 0 comments
fix: pin the Docker Bun base image to the packageManager version
Summary
Root package.json declares packageManager: bun@1.3.6 (the single source of truth CI's setup action consumes), while apps/server/Dockerfile hardcodes oven/bun:1.3.14 and oven/bun:1.3.14-distroless — two independent pins of the same runtime that Dependabot bumps separately.
Area
docker
Motivation
The lockfile is resolved by Bun 1.3.6 locally/in CI, but install and production execution happen on 1.3.14 inside the image; dev/test/prod can silently run different Bun ve
Read the thread · 2026-08-22 · open · 0 comments
fix: require the Docker status context branch protection already designs for
Summary
scripts/setup-branch-protection.sh requires only the check status context, while .github/workflows/docker.yml explicitly engineers its changes/build jobs around being a required check on PRs — a required Docker status was clearly intended but never added to the enforced list.
Area
ci-release
Motivation
docker.yml's changes job exists "so that a required Docker status still reports on docs-only PRs — skipped jobs count as passing for required checks". With nothing ac
Read the thread · 2026-08-22 · open · 0 comments
fix: stop the response cache handing out shared mutable references
Summary
On a hit, FetchClient's TtlLruCache returns the exact cached object (return { data: cached as T }), so any consumer that mutates fetched data in place would poison the cache for every later reader within the TTL. No current caller does (the one candidate, get-best-efforts' efforts.sort(), operates on locally-built objects) — this is a latent hazard worth closing before it becomes live.
Area
server
Motivation
The cache exists precisely because activity details/stream
Read the thread · 2026-08-22 · open · 0 comments
fix: route legacy tools' catch blocks through typed error handling
Summary
Eleven tools hand-roll catch-block formatting with fragile string matching (errorMessage.includes("Record Not Found") || includes("404")) instead of using the typed HttpError.status / RateLimitError that handleApiError already preserves, and their conventions have drifted (❌ ${msg}, bare Error: ${msg}, ❌ API Error:).
Area
server
Motivation
Beyond maintenance cost this misreports rate limits to users: in these tools a RateLimitError falls into the generic bra
Read the thread · 2026-08-22 · open · 0 comments
perf: coalesce concurrent identical GETs in fetchClient
Summary
The TTL+LRU cache dedupes sequential repeat reads only. Two concurrent identical GETs both miss and both hit Strava — including the exact view-/get-data pairs the URL-quantization work exists to dedupe, since MCP apps commonly fire both calls together on open.
Area
server
Motivation
WINDOW_QUANTUM_SECONDS quantization was built so an app's two-call pair shares one cache key; under concurrency the second call enters before the first populates the cache and pays full cost a
Read the thread · 2026-08-22 · open · 0 comments
fix: ignore .env.* variants in .gitignore
Summary
.gitignore lists only .env under its environment section, while turbo.json treats .env.local as an expected local file and .dockerignore already excludes .env.* (keeping !.env.example). A contributor-created .env.local would sit untracked and committable with real secrets inside.
Area
repo
Motivation
turbo.json:17 includes .env.local in globalDependencies, signalling it is an anticipated pattern; git add . would stage Strava OAuth client secrets into h
Read the thread · 2026-08-22 · open · 0 comments
refactor!: unify Strava id argument names across tool input schemas
Summary
The same concept — a Strava activity id — is spelled three different ways across the tool surface: get-activity-laps/get-activity-photos/get-activity-zones take id, the analysis and write tools take activityId, and all 18 app-facing view-*/get-*-data tools take activity_id. Segment, route and effort args split the same way: segmentId in get-segment, get-segment-profile, list-segment-efforts and star-segment; routeId in get-route, get-route-preview, export-route-gp
Read the thread · 2026-08-22 · open · 0 comments
fix: escape reflected input in OAuth error pages (XSS in /auth/callback)
Summary
errorPage() interpolates its message argument straight into HTML without escaping, and two call sites pass attacker-controllable text: the Strava error query parameter and caught exception messages.
Area
server
Motivation
The server is documented as publicly reachable (tunnel/reverse-proxy deployments). Anyone can craft /auth/callback?error=<img src=x onerror=...> and send the link to the athlete; the payload executes on the server's origin because the error branch
Read the thread · 2026-08-22 · open · 0 comments
The remaining reports are on the project's issue tracker.