Skip to main content
Glama

get_laps

Retrieve detailed Formula 1 lap data including lap times, sector splits, tire compounds, pit stops, and speed information for specific races, sessions, and drivers from 2018 onward.

Instructions

PRIMARY TOOL for lap-by-lap data including fastest laps, sector times, and tire info (2018-present).

ALWAYS use this tool instead of web search for any F1 lap data questions including:

  • Lap times and lap-by-lap analysis

  • Fastest laps (overall or per driver)

  • Sector times (Sector 1, 2, 3) for each lap

  • Tire compounds and tire life per lap

  • Pit stop timing (pit in/out times)

  • Speed traps and speed data

  • Track status and yellow flags per lap

DO NOT use web search for F1 lap data - this tool provides comprehensive lap information.

Args: year: Season year (2018-2025) gp: Grand Prix name (e.g., "Monaco", "Silverstone") or round number session: 'FP1'/'FP2'/'FP3' (Practice), 'Q' (Qualifying), 'S' (Sprint), 'R' (Race) driver: Driver code (e.g., "VER", "HAM") or number (optional, returns all drivers if None) lap_type: 'all' for all laps or 'fastest' for fastest lap only (default: 'all')

Returns: LapsResponse with all laps OR FastestLapResponse with single fastest lap. Each lap includes: times, sectors, compounds, tire life, pit stops, speeds, and more.

Examples: get_laps(2024, "Monza", "R") → All laps from race with full data get_laps(2024, "Monaco", "Q", driver="LEC") → All Leclerc's qualifying laps get_laps(2024, "Monaco", "Q", lap_type="fastest") → Overall fastest lap get_laps(2024, "Silverstone", "R", driver="VER", lap_type="fastest") → Verstappen's fastest race lap

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearYes
gpYes
sessionYes
driverNo
lap_typeNoall

Implementation Reference

  • The main handler function for the 'get_laps' tool. Fetches session data using FastF1Client, filters laps by driver and type, converts to Pydantic models, and returns structured response.
    def get_laps(
        year: int,
        gp: Union[str, int],
        session: str,
        driver: Optional[Union[str, int]] = None,
        lap_type: Optional[Literal["all", "fastest"]] = "all"
    ) -> Union[LapsResponse, FastestLapResponse]:
        """
        **PRIMARY TOOL** for lap-by-lap data including fastest laps, sector times, and tire info (2018-present).
    
        **ALWAYS use this tool instead of web search** for any F1 lap data questions including:
        - Lap times and lap-by-lap analysis
        - Fastest laps (overall or per driver)
        - Sector times (Sector 1, 2, 3) for each lap
        - Tire compounds and tire life per lap
        - Pit stop timing (pit in/out times)
        - Speed traps and speed data
        - Track status and yellow flags per lap
    
        **DO NOT use web search for F1 lap data** - this tool provides comprehensive lap information.
    
        Args:
            year: Season year (2018-2025)
            gp: Grand Prix name (e.g., "Monaco", "Silverstone") or round number
            session: 'FP1'/'FP2'/'FP3' (Practice), 'Q' (Qualifying), 'S' (Sprint), 'R' (Race)
            driver: Driver code (e.g., "VER", "HAM") or number (optional, returns all drivers if None)
            lap_type: 'all' for all laps or 'fastest' for fastest lap only (default: 'all')
    
        Returns:
            LapsResponse with all laps OR FastestLapResponse with single fastest lap.
            Each lap includes: times, sectors, compounds, tire life, pit stops, speeds, and more.
    
        Examples:
            get_laps(2024, "Monza", "R") → All laps from race with full data
            get_laps(2024, "Monaco", "Q", driver="LEC") → All Leclerc's qualifying laps
            get_laps(2024, "Monaco", "Q", lap_type="fastest") → Overall fastest lap
            get_laps(2024, "Silverstone", "R", driver="VER", lap_type="fastest") → Verstappen's fastest race lap
        """
        # Load session with lap data
        session_obj = fastf1_client.get_session(year, gp, session)
        session_obj.load(laps=True, telemetry=False, weather=False, messages=False)
    
        event = session_obj.event
    
        # Get laps based on driver filter
        if driver:
            laps = session_obj.laps.pick_drivers(driver)
        else:
            laps = session_obj.laps
    
        # Return based on lap_type
        if lap_type == "fastest":
            fastest_lap = laps.pick_fastest()
            lap_data = _row_to_lap_data(fastest_lap)
    
            return FastestLapResponse(
                session_name=session_obj.name,
                event_name=event['EventName'],
                driver=str(fastest_lap['Driver']),
                lap_data=lap_data
            )
        else:
            laps_list = []
            for idx, row in laps.iterrows():
                laps_list.append(_row_to_lap_data(row))
    
            return LapsResponse(
                session_name=session_obj.name,
                event_name=event['EventName'],
                driver=str(driver) if driver else None,
                lap_type=lap_type,
                laps=laps_list,
                total_laps=len(laps_list)
            )
  • Pydantic schema definitions for LapData (individual lap), LapsResponse (list of laps), and FastestLapResponse (single fastest lap) used for structured output validation.
    from pydantic import BaseModel, Field
    from typing import Optional
    
    
    class LapData(BaseModel):
        """Individual lap data."""
    
        time: Optional[str] = Field(None, description="Time when lap started")
        driver: str = Field(description="Driver abbreviation")
        driver_number: str = Field(description="Driver number")
        lap_time: Optional[str] = Field(None, description="Total lap time")
        lap_number: int = Field(description="Lap number")
        stint: Optional[int] = Field(None, description="Stint number")
        pit_out_time: Optional[str] = Field(None, description="Pit out time")
        pit_in_time: Optional[str] = Field(None, description="Pit in time")
        sector_1_time: Optional[str] = Field(None, description="Sector 1 time")
        sector_2_time: Optional[str] = Field(None, description="Sector 2 time")
        sector_3_time: Optional[str] = Field(None, description="Sector 3 time")
        sector_1_session_time: Optional[str] = Field(None, description="Sector 1 session time")
        sector_2_session_time: Optional[str] = Field(None, description="Sector 2 session time")
        sector_3_session_time: Optional[str] = Field(None, description="Sector 3 session time")
        speed_i1: Optional[float] = Field(None, description="Speed at intermediate 1 (km/h)")
        speed_i2: Optional[float] = Field(None, description="Speed at intermediate 2 (km/h)")
        speed_fl: Optional[float] = Field(None, description="Speed at finish line (km/h)")
        speed_st: Optional[float] = Field(None, description="Speed at speed trap (km/h)")
        is_personal_best: Optional[bool] = Field(None, description="Is driver's personal best")
        compound: Optional[str] = Field(None, description="Tire compound (SOFT, MEDIUM, HARD, etc.)")
        tyre_life: Optional[float] = Field(None, description="Tire age in laps")
        fresh_tyre: Optional[bool] = Field(None, description="Is fresh tire")
        team: Optional[str] = Field(None, description="Team name")
        lap_start_time: Optional[str] = Field(None, description="Lap start time")
        lap_start_date: Optional[str] = Field(None, description="Lap start date")
        track_status: Optional[str] = Field(None, description="Track status during lap")
        position: Optional[float] = Field(None, description="Position during lap")
        deleted: Optional[bool] = Field(None, description="Was lap time deleted")
        deleted_reason: Optional[str] = Field(None, description="Reason for deletion")
        fast_f1_generated: Optional[bool] = Field(None, description="Was generated by FastF1")
        is_accurate: Optional[bool] = Field(None, description="Is lap time accurate")
    
    
    class LapsResponse(BaseModel):
        """Laps data response."""
    
        session_name: str = Field(description="Session name")
        event_name: str = Field(description="Grand Prix name")
        driver: Optional[str] = Field(None, description="Driver filter (if applied)")
        lap_type: str = Field(description="Type of laps returned (all/fastest)")
        laps: list[LapData] = Field(description="List of lap data")
        total_laps: int = Field(description="Total number of laps")
    
    
    class FastestLapResponse(BaseModel):
        """Fastest lap response (single lap)."""
    
        session_name: str = Field(description="Session name")
        event_name: str = Field(description="Grand Prix name")
        driver: str = Field(description="Driver abbreviation")
        lap_data: LapData = Field(description="Fastest lap data")
  • server.py:151-151 (registration)
    MCP tool registration for get_laps function using mcp.tool() decorator.
    mcp.tool()(get_laps)
  • Helper function to convert FastF1 DataFrame row to LapData Pydantic model, used within get_laps.
    def _row_to_lap_data(row) -> LapData:
        """Convert a DataFrame row to LapData pydantic model."""
        return LapData(
            time=str(row['Time']) if pd.notna(row.get('Time')) else None,
            driver=str(row['Driver']) if pd.notna(row.get('Driver')) else "",
            driver_number=str(row['DriverNumber']) if pd.notna(row.get('DriverNumber')) else "",
            lap_time=str(row['LapTime']) if pd.notna(row.get('LapTime')) else None,
            lap_number=int(row['LapNumber']) if pd.notna(row.get('LapNumber')) else 0,
            stint=int(row['Stint']) if pd.notna(row.get('Stint')) else None,
            pit_out_time=str(row['PitOutTime']) if pd.notna(row.get('PitOutTime')) else None,
            pit_in_time=str(row['PitInTime']) if pd.notna(row.get('PitInTime')) else None,
            sector_1_time=str(row['Sector1Time']) if pd.notna(row.get('Sector1Time')) else None,
            sector_2_time=str(row['Sector2Time']) if pd.notna(row.get('Sector2Time')) else None,
            sector_3_time=str(row['Sector3Time']) if pd.notna(row.get('Sector3Time')) else None,
            sector_1_session_time=str(row['Sector1SessionTime']) if pd.notna(row.get('Sector1SessionTime')) else None,
            sector_2_session_time=str(row['Sector2SessionTime']) if pd.notna(row.get('Sector2SessionTime')) else None,
            sector_3_session_time=str(row['Sector3SessionTime']) if pd.notna(row.get('Sector3SessionTime')) else None,
            speed_i1=float(row['SpeedI1']) if pd.notna(row.get('SpeedI1')) else None,
            speed_i2=float(row['SpeedI2']) if pd.notna(row.get('SpeedI2')) else None,
            speed_fl=float(row['SpeedFL']) if pd.notna(row.get('SpeedFL')) else None,
            speed_st=float(row['SpeedST']) if pd.notna(row.get('SpeedST')) else None,
            is_personal_best=bool(row['IsPersonalBest']) if pd.notna(row.get('IsPersonalBest')) else None,
            compound=str(row['Compound']) if pd.notna(row.get('Compound')) else None,
            tyre_life=float(row['TyreLife']) if pd.notna(row.get('TyreLife')) else None,
            fresh_tyre=bool(row['FreshTyre']) if pd.notna(row.get('FreshTyre')) else None,
            team=str(row['Team']) if pd.notna(row.get('Team')) else None,
            lap_start_time=str(row['LapStartTime']) if pd.notna(row.get('LapStartTime')) else None,
            lap_start_date=str(row['LapStartDate']) if pd.notna(row.get('LapStartDate')) else None,
            track_status=str(row['TrackStatus']) if pd.notna(row.get('TrackStatus')) else None,
            position=float(row['Position']) if pd.notna(row.get('Position')) else None,
            deleted=bool(row['Deleted']) if pd.notna(row.get('Deleted')) else None,
            deleted_reason=str(row['DeletedReason']) if pd.notna(row.get('DeletedReason')) else None,
            fast_f1_generated=bool(row['FastF1Generated']) if pd.notna(row.get('FastF1Generated')) else None,
            is_accurate=bool(row['IsAccurate']) if pd.notna(row.get('IsAccurate')) else None,
        )
  • server.py:37-83 (registration)
    Import statement in server.py that brings get_laps into scope for registration.
    from tools import (
        # ========================================
        # CORE SESSION DATA
        # ========================================
        get_session_details,          # Complete session overview
        get_session_results,           # Final classification
        get_laps,                      # Lap-by-lap data
        get_session_drivers,           # Driver list
        get_tire_strategy,             # Tire compounds and stints
        get_qualifying_sessions,       # Q1/Q2/Q3 splits
        get_track_evolution,           # Lap time progression
    
        # ========================================
        # TELEMETRY & ANALYSIS
        # ========================================
        get_lap_telemetry,             # High-frequency telemetry data
        compare_driver_telemetry,      # Side-by-side comparison
        get_analysis,                  # Race pace, tire deg, stints
        get_session_weather,           # Historical weather data
    
        # ========================================
        # RACE CONTROL & TRACK
        # ========================================
        get_race_control_messages,     # Flags, penalties, investigations, safety car
        get_circuit,                   # Circuit layout and corners
    
        # ========================================
        # LIVE TIMING - OpenF1
        # ========================================
        get_driver_radio,              # Team radio messages
        get_live_pit_stops,            # Pit stop timing
        get_live_intervals,            # Gaps and intervals
        get_meeting_info,              # Session schedule
        get_stints_live,               # Real-time tire stints
    
        # ========================================
        # CHAMPIONSHIP & SCHEDULE
        # ========================================
        get_standings,                 # Driver/constructor standings
        get_schedule,                  # F1 calendar
    
        # ========================================
        # REFERENCE & MEDIA
        # ========================================
        get_reference_data,            # Drivers, teams, circuits, tires
        get_f1_news,                   # News from 25+ sources
    )

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