MCP server that exposes Strava API endpoints as tools for a running coach agent, enabling Claude to analyze athlete training data, provide coaching recommendations, and manage long-term memory about athletes.
Server has 9 tools with mostly complete schemas and descriptions. Naming follows verb_noun convention (get_*, list_*, save_*). Descriptions are detailed and contextual, averaging ~180 chars, well within the 10-1024 baseline. All parameters have type definitions and descriptions. However, output schemas are not explicitly documented in the code, responses are JSON-serialized but the structure is inferred from Strava API docs rather than declared in tool definitions. Error handling is minimal; no recovery guidance or error categorization. The save_memory tool lacks input validation and error responses. Tool composition is sound (single responsibility), but some tools like list_activities are complex with implicit dependencies (must call get_current_timestamp first). No tool annotations (readOnlyHint/destructiveHint) despite clear risk profiles.
Get coaching-relevant details of a specific activity by its Strava ID. Returns everything in list_activities PLUS: description, calories, perceived_exertion, splits_metric (per-km splits with pace and HR), best_efforts (PRs at standard distances), gear (shoe/bike used). Noisy fields (map polylines, segment efforts, splits_imperial, social counts) are stripped to keep the response compact. Use get_activity_laps for full lap data. Use this after list_activities to drill into a specific run for detailed analysis.
Get lap-by-lap data for an activity. Each lap includes: lap_index, distance, moving_time, elapsed_time, average_speed, max_speed, average_heartrate, max_heartrate, average_cadence, total_elevation_gain. Essential for analysing interval workouts, tempo runs, and paced efforts. Distances in metres, times in seconds, speed in m/s.
Get heart rate and pace zone distribution for a specific activity. Shows what percentage of the run was spent in each HR/pace zone. Useful for determining aerobic vs anaerobic training load. Note: requires Strava Premium and a heart rate monitor. Returns an error dict if zone data is unavailable.
Get the authenticated athlete's profile: name, location, weight, FTP, sex, measurement preference (metric/imperial), and follower counts.
Output schemas not documented. Tool descriptions explain what fields are returned (e.g., 'Each activity includes: id, name, type...'), but no formal JSON Schema output definitions exist in the code. LLMs cannot plan downstream tool calls without knowing the response structure.
No error handling or recovery guidance. Tools return raw JSON from Strava API without categorizing errors as retryable, user-fixable, or fatal. E.g., get_activity_zones notes 'Returns an error dict if zone data is unavailable' but provides no guidance on what the LLM should do next.
save_memory lacks input validation and error responses. No constraints on fact length, format, or content. No error handling if the memory backend fails. LLM has no guidance if the save fails.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 55 | <=2025-11-25 | v2 |
Get the athlete's overall training statistics including: recent_run_totals: distance, moving_time, elevation_gain for the last 4 weeks; ytd_run_totals: year-to-date totals; all_run_totals: lifetime totals. All distances are in metres, times in seconds.
Get the athlete's configured heart rate and power zones. Heart rate zones are defined by min/max bpm boundaries. Useful for zone-based training analysis.
Return the current Unix timestamp and human-readable UTC date. Always call this before computing date ranges for list_activities.
List the athlete's activities (summary level). Always call get_current_timestamp() first to get the current date and Unix time. Use the returned unix_timestamp as the anchor for all date-range calculations. For queries about the user's "latest", "current", or "today's" run, anchor after_timestamp to the current year to avoid returning last year's data. For trend or pattern analysis, use whatever date range the question requires. Each activity includes: id, name, type, sport_type, workout_type, start_date, start_date_local, distance (metres), moving_time (seconds), total_elevation_gain (metres), average_speed (m/s), average_heartrate, max_heartrate, average_cadence, suffer_score, pr_count. Use after_timestamp / before_timestamp (Unix epoch integers) to filter by date range. Use page to paginate results. per_page max is 200. Default is 10 to keep response size manageable; increase only when a broader history is needed. To get runs from the last 30 days, compute after_timestamp as (current Unix time - 2592000).
Save an important fact about this athlete to long-term memory. Call this when the athlete mentions something worth remembering across conversations: goals, race targets, injury history, training preferences, schedule constraints, personal bests, or measurement preference (metric/imperial). Do not save generic training advice — only athlete-specific facts.
No tool annotations (readOnlyHint/destructiveHint/idempotentHint). All read-only tools (get_*, list_*) should declare readOnlyHint=true; save_memory should declare destructiveHint=true (modifies state). Annotations help agents reason about side effects and retry safety.
Implicit tool dependencies not formalized. list_activities description says 'Always call get_current_timestamp() first' but this is a prose instruction, not a formal dependency declaration. LLMs may skip the prerequisite call.