Skip to main content
Glama

get_track_evolution

Analyze Formula 1 lap time improvements during sessions to visualize track evolution and rubbering-in effects across practice, qualifying, and race data.

Instructions

Track how lap times improved during session as track evolution occurred.

Shows fastest lap per lap number to see track rubbering in and improvement.

Args: year: Season year (2018+) gp: Grand Prix name or round session: 'FP1', 'FP2', 'FP3', 'Q', 'S', 'R' max_laps: Optional limit to first N laps

Returns: TrackEvolutionResponse with lap-by-lap improvement data

Example: get_track_evolution(2024, "Monaco", "FP1") → Practice track evolution get_track_evolution(2024, "Monaco", "Q", 20) → First 20 laps of qualifying

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearYes
gpYes
sessionYes
max_lapsNo

Implementation Reference

  • Main handler function that loads F1 session data using FastF1, filters valid laps, finds the fastest lap time for each lap number across drivers, computes improvement from the first lap's best time, and structures the output using defined Pydantic models.
    def get_track_evolution(
        year: int,
        gp: Union[str, int],
        session: str,
        max_laps: Optional[int] = None
    ) -> TrackEvolutionResponse:
        """
        Track how lap times improved during session as track evolution occurred.
    
        Shows fastest lap per lap number to see track rubbering in and improvement.
    
        Args:
            year: Season year (2018+)
            gp: Grand Prix name or round
            session: 'FP1', 'FP2', 'FP3', 'Q', 'S', 'R'
            max_laps: Optional limit to first N laps
    
        Returns:
            TrackEvolutionResponse with lap-by-lap improvement data
    
        Example:
            get_track_evolution(2024, "Monaco", "FP1") → Practice track evolution
            get_track_evolution(2024, "Monaco", "Q", 20) → First 20 laps of qualifying
        """
        session_obj = fastf1_client.get_session(year, gp, session)
        session_obj.load(laps=True, telemetry=False, weather=False, messages=False)
    
        event = session_obj.event
        laps = session_obj.laps
    
        # Filter for valid laps only (not deleted, not pit laps)
        valid_laps = laps[
            (laps['IsAccurate'] == True) &
            (laps['Deleted'] == False) &
            (pd.notna(laps['LapTime']))
        ].copy()
    
        if len(valid_laps) == 0:
            return TrackEvolutionResponse(
                session_name=session_obj.name,
                event_name=event['EventName'],
                evolution=[],
                total_laps=0,
                total_improvement=None
            )
    
        # Convert LapTime to seconds for comparison
        valid_laps['LapTimeSeconds'] = valid_laps['LapTime'].dt.total_seconds()
    
        # Group by lap number and find fastest for each lap
        evolution_data = []
        lap_numbers = sorted(valid_laps['LapNumber'].unique())
    
        if max_laps:
            lap_numbers = [ln for ln in lap_numbers if ln <= max_laps]
    
        first_lap_best = None
    
        for lap_num in lap_numbers:
            lap_data = valid_laps[valid_laps['LapNumber'] == lap_num]
            fastest_idx = lap_data['LapTimeSeconds'].idxmin()
            fastest_lap = lap_data.loc[fastest_idx]
    
            if first_lap_best is None:
                first_lap_best = fastest_lap['LapTimeSeconds']
                improvement = None
            else:
                improvement = first_lap_best - fastest_lap['LapTimeSeconds']
    
            evolution_data.append(
                LapEvolution(
                    lap_number=int(lap_num),
                    best_time=str(fastest_lap['LapTime']),
                    driver=str(fastest_lap['Driver']),
                    driver_number=str(fastest_lap['DriverNumber']),
                    improvement_from_lap_1=improvement
                )
            )
    
        # Calculate total improvement
        total_improvement = None
        if len(evolution_data) >= 2 and evolution_data[-1].improvement_from_lap_1 is not None:
            total_improvement = evolution_data[-1].improvement_from_lap_1
    
        return TrackEvolutionResponse(
            session_name=session_obj.name,
            event_name=event['EventName'],
            evolution=evolution_data,
            total_laps=len(evolution_data),
            total_improvement=total_improvement
        )
  • Pydantic models defining the structure of lap evolution data points and the overall response for the tool.
    class LapEvolution(BaseModel):
        """Lap time evolution data point."""
        lap_number: int = Field(..., description="Lap number")
        best_time: str = Field(..., description="Best lap time for this lap number across all drivers")
        driver: str = Field(..., description="Driver who set this time")
        driver_number: str = Field(..., description="Driver number")
        improvement_from_lap_1: Optional[float] = Field(None, description="Seconds faster than lap 1 best")
    
    
    class TrackEvolutionResponse(BaseModel):
        """Response for track evolution data."""
        session_name: str = Field(..., description="Session name")
        event_name: str = Field(..., description="Event name")
        evolution: list[LapEvolution] = Field(..., description="Lap time evolution throughout session")
        total_laps: int = Field(..., description="Total number of laps analyzed")
        total_improvement: Optional[float] = Field(None, description="Total improvement in seconds from start to end")
  • server.py:155-155 (registration)
    Registers the get_track_evolution function as an MCP tool using the FastMCP tool decorator.
    mcp.tool()(get_track_evolution)

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/praneethravuri/pitstop'

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