Skip to main content
Glama

explore-segments

Find popular running and cycling segments within a specific geographical area to discover new routes and challenges.

Instructions

Searches for popular segments within a given geographical area.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
boundsYesThe geographical area to search, specified as a comma-separated string: south_west_lat,south_west_lng,north_east_lat,north_east_lng
activityTypeNoFilter segments by activity type (optional: 'running' or 'riding').
minCatNoFilter by minimum climb category (optional, 0-5). Requires riding activityType.
maxCatNoFilter by maximum climb category (optional, 0-5). Requires riding activityType.

Implementation Reference

  • The 'exploreSegments' constant defines the tool name, description, schema, and the 'execute' function which contains the tool's core logic for interacting with the Strava API.
    export const exploreSegments = {
        name: "explore-segments",
        description: "Searches for popular segments within a given geographical area.",
        inputSchema: ExploreSegmentsInputSchema,
        execute: async ({ bounds, activityType, minCat, maxCat }: ExploreSegmentsInput) => {
            const token = process.env.STRAVA_ACCESS_TOKEN;
    
            if (!token || token === 'YOUR_STRAVA_ACCESS_TOKEN_HERE') {
                console.error("Missing or placeholder 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,
                };
            }
            if ((minCat !== undefined || maxCat !== undefined) && activityType !== 'riding') {
                return {
                    content: [{ type: "text" as const, text: "❌ Input Error: Climb category filters (minCat, maxCat) require activityType to be 'riding'." }],
                    isError: true,
                };
            }
    
            try {
                console.error(`Exploring segments within bounds: ${bounds}...`);
                const athlete = await getAuthenticatedAthlete(token);
                const response: StravaExplorerResponse = await fetchExploreSegments(token, bounds, activityType, minCat, maxCat);
                console.error(`Found ${response.segments?.length ?? 0} segments.`);
    
                if (!response.segments || response.segments.length === 0) {
                    return { content: [{ type: "text" as const, text: " MNo segments found in the specified area with the given filters." }] };
                }
    
                const distanceFactor = athlete.measurement_preference === 'feet' ? 0.000621371 : 0.001;
                const distanceUnit = athlete.measurement_preference === 'feet' ? 'mi' : 'km';
                const elevationFactor = athlete.measurement_preference === 'feet' ? 3.28084 : 1;
                const elevationUnit = athlete.measurement_preference === 'feet' ? 'ft' : 'm';
    
                const segmentItems = response.segments.map(segment => {
                    const distance = (segment.distance * distanceFactor).toFixed(2);
                    const elevDifference = (segment.elev_difference * elevationFactor).toFixed(0);
                    const text = `
    🗺️ **${segment.name}** (ID: ${segment.id})
       - Climb: Cat ${segment.climb_category_desc} (${segment.climb_category})
       - Distance: ${distance} ${distanceUnit}
       - Avg Grade: ${segment.avg_grade}%
       - Elev Difference: ${elevDifference} ${elevationUnit}
       - Starred: ${segment.starred ? 'Yes' : 'No'}
                    `.trim();
                    const item: { type: "text", text: string } = { type: "text" as const, text };
                    return item;
                });
    
                const responseText = `**Found Segments:**\n\n${segmentItems.map(item => item.text).join("\n---\n")}`;
    
                return { content: [{ type: "text" as const, text: responseText }] };
            } catch (error) {
                const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
                console.error("Error in explore-segments tool:", errorMessage);
                return {
                    content: [{ type: "text" as const, text: `❌ API Error: ${errorMessage}` }],
                    isError: true,
                };
            }
        }
    };
  • The 'ExploreSegmentsInputSchema' defines the Zod schema for the tool's input parameters, including validation for geographic bounds and activity type filters.
    const ExploreSegmentsInputSchema = z.object({
        bounds: z.string()
            .regex(/^-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?$/, "Bounds must be in the format: south_west_lat,south_west_lng,north_east_lat,north_east_lng")
            .describe("The geographical area to search, specified as a comma-separated string: south_west_lat,south_west_lng,north_east_lat,north_east_lng"),
        activityType: z.enum(["running", "riding"])
            .optional()
            .describe("Filter segments by activity type (optional: 'running' or 'riding')."),
        minCat: z.number().int().min(0).max(5).optional()
            .describe("Filter by minimum climb category (optional, 0-5). Requires riding activityType."),
        maxCat: z.number().int().min(0).max(5).optional()
            .describe("Filter by maximum climb category (optional, 0-5). Requires riding activityType."),
    });

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