Skip to main content
Glama

list-athlete-routes

Retrieve and paginate routes created by the authenticated athlete using the Strava MCP Server. Specify page number and items per page to manage results efficiently.

Instructions

Lists the routes created by the authenticated athlete, with pagination.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pageNoPage number for pagination
perPageNoNumber of routes per page (max 50)

Implementation Reference

  • The execute function implementing the core tool logic: validates input, fetches routes from Strava API via helper, formats summaries, handles errors and returns formatted text response.
    execute: async ({ page = 1, perPage = 20 }: ListAthleteRoutesInput) => { const token = process.env.STRAVA_ACCESS_TOKEN; if (!token) { console.error("Missing STRAVA_ACCESS_TOKEN in .env"); return { content: [{ type: "text" as const, text: "❌ Configuration Error: STRAVA_ACCESS_TOKEN is missing or not set in the .env file." }], isError: true }; } try { console.error(`Fetching routes (page ${page}, per_page: ${perPage})...`); const routes = await fetchAthleteRoutes(token, page, perPage); if (!routes || routes.length === 0) { console.error(`No routes found for athlete.`); return { content: [{ type: "text" as const, text: "No routes found for the athlete." }] }; } console.error(`Successfully fetched ${routes.length} routes.`); const summaries = routes.map(route => formatRouteSummary(route)); const responseText = `**Athlete Routes (Page ${page}):**\n\n${summaries.join("\n")}`; return { content: [{ type: "text" as const, text: responseText }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Error listing athlete routes (page ${page}, perPage: ${perPage}): ${errorMessage}`); // Removed call to handleApiError and its retry logic // Note: 404 is less likely for a list endpoint like this const userFriendlyMessage = `An unexpected error occurred while listing athlete routes. Details: ${errorMessage}`; return { content: [{ type: "text" as const, text: `❌ ${userFriendlyMessage}` }], isError: true }; } } };
  • Zod input schema defining optional pagination parameters page and perPage for the tool.
    const ListAthleteRoutesInputSchema = z.object({ page: z.number().int().positive().optional().default(1).describe("Page number for pagination"), perPage: z.number().int().positive().min(1).max(50).optional().default(20).describe("Number of routes per page (max 50)"), });
  • src/server.ts:117-121 (registration)
    MCP server registration of the list-athlete-routes tool using its name, description, input schema, and execute handler.
    listAthleteRoutesTool.name, listAthleteRoutesTool.description, listAthleteRoutesTool.inputSchema?.shape ?? {}, listAthleteRoutesTool.execute );
  • Core helper function that performs the actual Strava API call to /athlete/routes, handles pagination, validation with Zod, error handling including token refresh.
    export async function listAthleteRoutes(accessToken: string, page = 1, perPage = 30): Promise<StravaRoute[]> { if (!accessToken) { throw new Error("Strava access token is required."); } try { const response = await stravaApi.get<unknown>("athlete/routes", { headers: { Authorization: `Bearer ${accessToken}` }, params: { page: page, per_page: perPage } }); const validationResult = StravaRoutesResponseSchema.safeParse(response.data); if (!validationResult.success) { console.error("Strava API validation failed (listAthleteRoutes):", validationResult.error); throw new Error(`Invalid data format received from Strava API: ${validationResult.error.message}`); } return validationResult.data; } catch (error) { return await handleApiError<StravaRoute[]>(error, 'listAthleteRoutes', async () => { // Use new token from environment after refresh const newToken = process.env.STRAVA_ACCESS_TOKEN!; return listAthleteRoutes(newToken, page, perPage); }); } }
  • Local helper function to format individual StravaRoute objects into readable markdown summaries.
    function formatRouteSummary(route: StravaRoute): string { const distance = route.distance ? `${(route.distance / 1000).toFixed(1)} km` : 'N/A'; const elevation = route.elevation_gain ? `${route.elevation_gain.toFixed(0)} m` : 'N/A'; return `🗺️ **${route.name}** (ID: ${route.id}) - Distance: ${distance} - Elevation: ${elevation} - Created: ${new Date(route.created_at).toLocaleDateString()} - Type: ${route.type === 1 ? 'Ride' : route.type === 2 ? 'Run' : 'Other'}`; }

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