Skip to main content
Glama

get-activity-laps

Retrieve detailed lap data for Strava activities to analyze performance metrics, track progress, and extract raw values for visualization.

Instructions

Retrieves detailed lap data for a specific Strava activity.

Use Cases:

  • Get complete lap data including timestamps, speeds, and metrics

  • Access raw values for detailed analysis or visualization

  • Extract specific lap metrics for comparison or tracking

Parameters:

  • id (required): The unique identifier of the Strava activity.

Output Format: Returns both a human-readable summary and complete JSON data for each lap, including:

  1. A text summary with formatted metrics

  2. Raw lap data containing all fields from the Strava API:

    • Unique lap ID and indices

    • Timestamps (start_date, start_date_local)

    • Distance and timing metrics

    • Speed metrics (average and max)

    • Performance metrics (heart rate, cadence, power if available)

    • Elevation data

    • Resource state information

    • Activity and athlete references

Notes:

  • Requires activity:read scope for public/followers activities, activity:read_all for private activities

  • Returns complete data as received from Strava API without omissions

  • All numeric values are preserved in their original precision

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idYesThe identifier of the activity to fetch laps for.

Implementation Reference

  • The tool handler for "get-activity-laps" which executes the logic, including fetching data from the Strava client and formatting the response.
    export const getActivityLapsTool = {
        name,
        description,
        inputSchema,
        execute: async ({ id }: GetActivityLapsInput) => {
            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 laps for activity ID: ${id}...`);
                const laps = await getActivityLapsClient(token, id);
    
                if (!laps || laps.length === 0) {
                    return {
                        content: [{ type: "text" as const, text: `✅ No laps found for activity ID: ${id}` }]
                    };
                }
    
                // Generate human-readable summary
                const lapSummaries = laps.map(lap => {
                    const details = [
                        `Lap ${lap.lap_index}: ${lap.name || 'Unnamed Lap'}`,
                        `  Time: ${formatDuration(lap.elapsed_time)} (Moving: ${formatDuration(lap.moving_time)})`,
                        `  Distance: ${(lap.distance / 1000).toFixed(2)} km`,
                        `  Avg Speed: ${lap.average_speed ? (lap.average_speed * 3.6).toFixed(2) + ' km/h' : 'N/A'}`,
                        `  Max Speed: ${lap.max_speed ? (lap.max_speed * 3.6).toFixed(2) + ' km/h' : 'N/A'}`,
                        lap.total_elevation_gain ? `  Elevation Gain: ${lap.total_elevation_gain.toFixed(1)} m` : null,
                        lap.average_heartrate ? `  Avg HR: ${lap.average_heartrate.toFixed(1)} bpm` : null,
                        lap.max_heartrate ? `  Max HR: ${lap.max_heartrate} bpm` : null,
                        lap.average_cadence ? `  Avg Cadence: ${lap.average_cadence.toFixed(1)} rpm` : null,
                        lap.average_watts ? `  Avg Power: ${lap.average_watts.toFixed(1)} W ${lap.device_watts ? '(Sensor)' : ''}` : null,
                    ];
                    return details.filter(d => d !== null).join('\n');
                });
    
                const summaryText = `Activity Laps Summary (ID: ${id}):\n\n${lapSummaries.join('\n\n')}`;
                
                // Add raw data section
                const rawDataText = `\n\nComplete Lap Data:\n${JSON.stringify(laps, null, 2)}`;
                
                console.error(`Successfully fetched ${laps.length} laps for activity ${id}`);
                
                return {
                    content: [
                        { type: "text" as const, text: summaryText },
                        { type: "text" as const, text: rawDataText }
                    ]
                };
            } catch (error) {
                const errorMessage = error instanceof Error ? error.message : String(error);
                console.error(`Error fetching laps for activity ${id}: ${errorMessage}`);
                const userFriendlyMessage = errorMessage.includes("Record Not Found") || errorMessage.includes("404")
                    ? `Activity with ID ${id} not found.`
                    : `An unexpected error occurred while fetching laps for activity ${id}. Details: ${errorMessage}`;
                return {
                    content: [{ type: "text" as const, text: `❌ ${userFriendlyMessage}` }],
                    isError: true
                };
            }
        }
    }; 
  • Input schema for the "get-activity-laps" tool using Zod.
    const inputSchema = z.object({
        id: z.union([z.number(), z.string()]).describe("The identifier of the activity to fetch laps for."),
    });
Behavior4/5

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

With no annotations provided, the description carries the full burden and does so well. It discloses important behavioral traits: authentication requirements ('Requires activity:read scope...'), data completeness ('Returns complete data... without omissions'), and precision handling ('All numeric values are preserved...'). It does not mention rate limits or error conditions, but covers key operational aspects.

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

Conciseness4/5

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

The description is well-structured with clear sections (Use Cases, Parameters, Output Format, Notes) and front-loaded purpose. It is appropriately sized for the tool's complexity, but could be slightly more concise by integrating some details (e.g., merging 'Output Format' bullet points). Every sentence adds value, with no redundant information.

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 the tool's moderate complexity (1 parameter, no output schema, no annotations), the description is largely complete. It covers purpose, usage, parameters, output details, and behavioral notes. However, it lacks explicit error handling information or examples of the output format, which would enhance completeness for an agent.

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

Parameters3/5

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

The schema description coverage is 100%, with the single parameter 'id' documented as 'The identifier of the activity to fetch laps for.' The description adds minimal value beyond this, only restating it as 'The unique identifier of the Strava activity.' No additional syntax, format, or validation details are provided, so the baseline score of 3 is appropriate.

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 states the tool's purpose with a specific verb ('Retrieves') and resource ('detailed lap data for a specific Strava activity'). It distinguishes itself from siblings like 'get-activity-details' or 'get-activity-streams' by focusing exclusively on lap data, not general activity information or raw sensor 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 description provides clear context for when to use this tool through the 'Use Cases' section, which outlines scenarios like detailed analysis, visualization, and metric comparison. However, it does not explicitly state when NOT to use it or name specific alternatives among the sibling tools (e.g., 'get-activity-details' for general info).

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

Install Server

Other Tools

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/LimeON-source/Strava-MCP'

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