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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
evolutionYesLap time evolution throughout session
event_nameYesEvent name
total_lapsYesTotal number of laps analyzed
session_nameYesSession name
total_improvementNoTotal improvement in seconds from start to end

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)
Behavior3/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes the tool's function and output ('lap-by-lap improvement data') but lacks details on permissions, rate limits, or error handling. It adds value by explaining the track evolution context and optional parameter usage, but does not fully cover behavioral traits like data freshness or constraints.

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

Conciseness5/5

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

The description is appropriately sized and front-loaded: it starts with the core purpose, adds details in a structured way with 'Args:' and 'Returns:' sections, and includes examples. Every sentence earns its place by providing essential information without redundancy, making it efficient and easy to scan.

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, no annotations, and an output schema present (TrackEvolutionResponse), the description is largely complete. It covers purpose, parameters, and return data context. However, it could improve by mentioning potential limitations or linking to sibling tools for related analyses, but the output schema reduces the need to detail return values.

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

Parameters5/5

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

Schema description coverage is 0%, so the description must compensate. It effectively adds meaning beyond the schema: it explains each parameter's purpose (e.g., 'year: Season year (2018+)', 'session: 'FP1', 'FP2', 'FP3', 'Q', 'S', 'R'', 'max_laps: Optional limit to first N laps'), provides examples, and clarifies the gp parameter accepts names or round numbers. This fully documents the parameters where the schema lacks descriptions.

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: 'Track how lap times improved during session as track evolution occurred' and 'Shows fastest lap per lap number to see track rubbering in and improvement.' It specifies the verb ('track', 'shows'), resource ('lap times', 'fastest lap per lap number'), and distinguishes it from siblings by focusing on track evolution analysis rather than telemetry, results, or other session data.

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: to analyze lap time improvements due to track evolution in specific sessions. It implies usage for practice or qualifying sessions (e.g., 'FP1', 'Q') but does not explicitly state when not to use it or name alternatives among siblings, such as get_laps or get_session_results, which might offer overlapping data.

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

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