get-activity-photos
Fetch photos from Strava activities to display, download, or analyze metadata including location and timestamps.
Instructions
Retrieves photos associated with a specific Strava activity.
Use Cases:
Fetch all photos uploaded to an activity
Get photo URLs for display or download
Access photo metadata including location and timestamps
Parameters:
id (required): The unique identifier of the Strava activity.
size (optional): Size of photos to return in pixels (e.g., 100, 600, 2048). If not specified, returns all available sizes.
Output Format: Returns both a human-readable summary and complete JSON data for each photo, including:
A text summary with photo count and URLs
Raw photo data containing all fields from the Strava API:
Photo ID and unique identifier
URLs for different sizes
Source (1 = Strava, 2 = Instagram)
Timestamps (uploaded_at, created_at)
Location coordinates if available
Caption if provided
Notes:
Requires activity:read scope for public/followers activities, activity:read_all for private activities
Photos may come from Strava uploads or linked Instagram posts
Returns empty array if activity has no photos
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The identifier of the activity to fetch photos for. | |
| size | No | Optional photo size in pixels (e.g., 100, 600, 2048). |
Implementation Reference
- src/tools/getActivityPhotos.ts:42-144 (handler)The main definition and implementation of the get-activity-photos tool. It handles input validation, calling the Strava client, and formatting the output.
export const getActivityPhotosTool = { name, description, inputSchema, execute: async ({ id, size }: GetActivityPhotosInput) => { 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 { // Convert id to number if it's a string const activityId = typeof id === 'string' ? parseInt(id, 10) : id; if (isNaN(activityId)) { return { content: [{ type: "text" as const, text: `Invalid activity ID: ${id}` }], isError: true }; } console.error(`Fetching photos for activity ID: ${activityId}...`); const photos = await getActivityPhotosClient(token, activityId, size); if (!photos || photos.length === 0) { return { content: [{ type: "text" as const, text: `No photos found for activity ID: ${activityId}` }] }; } // Generate human-readable summary const photoSummaries = photos.map((photo, index) => { const details = [ `Photo ${index + 1}${photo.id ? ` (ID: ${photo.id})` : ''}${photo.unique_id ? ` [${photo.unique_id}]` : ''}`, ]; // Add source info if (photo.source !== undefined) { const sourceText = photo.source === 1 ? 'Strava' : photo.source === 2 ? 'Instagram' : `Unknown (${photo.source})`; details.push(` Source: ${sourceText}`); } // Add caption if available if (photo.caption) { details.push(` Caption: ${photo.caption}`); } // Add location if available if (photo.location && photo.location.length === 2) { const lat = photo.location[0]; const lng = photo.location[1]; if (lat !== undefined && lng !== undefined) { details.push(` Location: ${lat.toFixed(6)}, ${lng.toFixed(6)}`); } } // Add timestamps if (photo.created_at) { details.push(` Created: ${photo.created_at}`); } // Add URLs if (photo.urls && Object.keys(photo.urls).length > 0) { details.push(` URLs:`); for (const [sizeKey, url] of Object.entries(photo.urls)) { details.push(` ${sizeKey}: ${url}`); } } return details.join('\n'); }); const summaryText = `Activity Photos (ID: ${activityId})\nTotal Photos: ${photos.length}\n\n${photoSummaries.join('\n\n')}`; // Add raw data section const rawDataText = `\n\nComplete Photo Data:\n${JSON.stringify(photos, null, 2)}`; console.error(`Successfully fetched ${photos.length} photos for activity ${activityId}`); 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 photos 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 photos for activity ${id}. Details: ${errorMessage}`; return { content: [{ type: "text" as const, text: `Error: ${userFriendlyMessage}` }], isError: true }; } } }; - src/tools/getActivityPhotos.ts:35-38 (schema)Zod schema for validating the input parameters of the get-activity-photos tool.
const inputSchema = z.object({ id: z.union([z.number(), z.string()]).describe("The identifier of the activity to fetch photos for."), size: z.number().int().positive().optional().describe("Optional photo size in pixels (e.g., 100, 600, 2048)."), }); - src/server.ts:189-189 (registration)Marker for where the get-activity-photos tool is registered in the server.
// --- Register get-activity-photos tool ---