Skip to main content
Glama

get-segment-effort

Retrieve detailed segment effort data by providing its unique ID. This tool enables analysis of specific Strava activity segments through the Strava MCP Server.

Instructions

Fetches detailed information about a specific segment effort using its ID.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
effortIdYesThe unique identifier of the segment effort to fetch.

Implementation Reference

  • The main handler for the 'get-segment-effort' tool. It fetches the segment effort from Strava API using the provided effortId, formats the details, and handles errors.
    export const getSegmentEffortTool = { name: "get-segment-effort", description: "Fetches detailed information about a specific segment effort using its ID.", inputSchema: GetSegmentEffortInputSchema, execute: async ({ effortId }: GetSegmentEffortInput) => { const token = process.env.STRAVA_ACCESS_TOKEN; if (!token) { console.error("Missing STRAVA_ACCESS_TOKEN environment variable."); return { content: [{ type: "text" as const, text: "Configuration error: Missing Strava access token." }], isError: true }; } try { console.error(`Fetching details for segment effort ID: ${effortId}...`); // Removed getAuthenticatedAthlete call const effort = await fetchSegmentEffort(token, effortId); const effortDetailsText = formatSegmentEffort(effort); // Use metric formatter console.error(`Successfully fetched details for effort: ${effort.name}`); return { content: [{ type: "text" as const, text: effortDetailsText }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Error fetching segment effort ${effortId}: ${errorMessage}`); let userFriendlyMessage; if (errorMessage.startsWith("SUBSCRIPTION_REQUIRED:")) { userFriendlyMessage = `🔒 Accessing this segment effort (ID: ${effortId}) requires a Strava subscription. Please check your subscription status.`; } else if (errorMessage.includes("Record Not Found") || errorMessage.includes("404")) { userFriendlyMessage = `Segment effort with ID ${effortId} not found.`; } else { userFriendlyMessage = `An unexpected error occurred while fetching segment effort ${effortId}. Details: ${errorMessage}`; } return { content: [{ type: "text" as const, text: `❌ ${userFriendlyMessage}` }], isError: true }; } } };
  • Zod input schema defining the expected input: effortId as positive integer.
    const GetSegmentEffortInputSchema = z.object({ effortId: z.number().int().positive().describe("The unique identifier of the segment effort to fetch.") });
  • src/server.ts:104-109 (registration)
    Registration of the 'get-segment-effort' tool on the MCP server using server.tool().
    server.tool( getSegmentEffortTool.name, getSegmentEffortTool.description, getSegmentEffortTool.inputSchema?.shape ?? {}, getSegmentEffortTool.execute );
  • Helper function to format the fetched segment effort into a readable string with key details.
    function formatSegmentEffort(effort: StravaDetailedSegmentEffort): string { const movingTime = formatDuration(effort.moving_time); const elapsedTime = formatDuration(effort.elapsed_time); const distance = formatDistance(effort.distance); // Remove speed/pace calculations as fields are not available on effort object // const avgSpeed = formatSpeed(effort.average_speed); // const maxSpeed = formatSpeed(effort.max_speed); // const avgPace = formatPace(effort.average_speed); let details = `⏱️ **Segment Effort: ${effort.name}** (ID: ${effort.id})\n`; details += ` - Activity ID: ${effort.activity.id}, Athlete ID: ${effort.athlete.id}\n`; details += ` - Segment ID: ${effort.segment.id}\n`; details += ` - Date: ${new Date(effort.start_date_local).toLocaleString()}\n`; details += ` - Moving Time: ${movingTime}, Elapsed Time: ${elapsedTime}\n`; if (effort.distance !== undefined) details += ` - Distance: ${distance}\n`; // Remove speed/pace display lines // if (effort.average_speed !== undefined) { ... } // if (effort.max_speed !== undefined) { ... } if (effort.average_cadence !== undefined && effort.average_cadence !== null) details += ` - Avg Cadence: ${effort.average_cadence.toFixed(1)}\n`; if (effort.average_watts !== undefined && effort.average_watts !== null) details += ` - Avg Watts: ${effort.average_watts.toFixed(1)}\n`; if (effort.average_heartrate !== undefined && effort.average_heartrate !== null) details += ` - Avg Heart Rate: ${effort.average_heartrate.toFixed(1)} bpm\n`; if (effort.max_heartrate !== undefined && effort.max_heartrate !== null) details += ` - Max Heart Rate: ${effort.max_heartrate.toFixed(0)} bpm\n`; if (effort.kom_rank !== null) details += ` - KOM Rank: ${effort.kom_rank}\n`; if (effort.pr_rank !== null) details += ` - PR Rank: ${effort.pr_rank}\n`; details += ` - Hidden: ${effort.hidden ? 'Yes' : 'No'}\n`; return details; }
  • Helper function to format time durations in HH:MM:SS or MM:SS format.
    function formatDuration(seconds: number | null | undefined): string { if (seconds === null || seconds === undefined || isNaN(seconds) || seconds < 0) return 'N/A'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); const parts: string[] = []; if (hours > 0) parts.push(hours.toString().padStart(2, '0')); parts.push(minutes.toString().padStart(2, '0')); parts.push(secs.toString().padStart(2, '0')); return parts.join(':'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/r-huijts/strava-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server