Skip to main content
Glama

get_schedule

Retrieve Formula 1 race calendars, session schedules, and event details for specific seasons or upcoming races using authoritative F1 data.

Instructions

PRIMARY TOOL for ALL Formula 1 calendar and schedule queries.

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

  • "When is the next race?" / upcoming race dates

  • Full season calendar and race schedule

  • Specific GP dates, times, and locations

  • Session schedules (practice, qualifying, race times)

  • Track/circuit information

  • Testing sessions and dates

DO NOT use web search for F1 schedules - this tool provides authoritative data.

Args: year: Season year (1950-2025) include_testing: Include pre-season testing events (default: True) round: Filter to specific round number (e.g., 5 for round 5) event_name: Filter by GP name (e.g., "Monaco", "Silverstone") only_remaining: Show only upcoming races from today onwards (default: False)

Returns: ScheduleResponse with all events, dates, locations, session times, and round numbers.

Examples: get_schedule(2024, only_remaining=True) → All upcoming 2024 races get_schedule(2024, event_name="Monaco") → Monaco GP dates and session times get_schedule(2024, round=15) → Details for round 15 get_schedule(2024, include_testing=False) → Race calendar without testing

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearYes
include_testingNo
roundNo
event_nameNo
only_remainingNo

Implementation Reference

  • The primary handler function for the 'get_schedule' tool. Fetches F1 event schedule data from FastF1Client, applies filters (year, round, event_name, only_remaining), converts to Pydantic models, and returns ScheduleResponse.
    def get_schedule(
        year: int,
        include_testing: bool = True,
        round: Optional[int] = None,
        event_name: Optional[str] = None,
        only_remaining: bool = False,
    ) -> ScheduleResponse:
        """
        **PRIMARY TOOL** for ALL Formula 1 calendar and schedule queries.
    
        **ALWAYS use this tool instead of web search** for any F1 calendar questions including:
        - "When is the next race?" / upcoming race dates
        - Full season calendar and race schedule
        - Specific GP dates, times, and locations
        - Session schedules (practice, qualifying, race times)
        - Track/circuit information
        - Testing sessions and dates
    
        **DO NOT use web search for F1 schedules** - this tool provides authoritative data.
    
        Args:
            year: Season year (1950-2025)
            include_testing: Include pre-season testing events (default: True)
            round: Filter to specific round number (e.g., 5 for round 5)
            event_name: Filter by GP name (e.g., "Monaco", "Silverstone")
            only_remaining: Show only upcoming races from today onwards (default: False)
    
        Returns:
            ScheduleResponse with all events, dates, locations, session times, and round numbers.
    
        Examples:
            get_schedule(2024, only_remaining=True) → All upcoming 2024 races
            get_schedule(2024, event_name="Monaco") → Monaco GP dates and session times
            get_schedule(2024, round=15) → Details for round 15
            get_schedule(2024, include_testing=False) → Race calendar without testing
        """
        # Get full event schedule
        if only_remaining:
            schedule_df = fastf1_client.get_events_remaining(
                dt=datetime.now(),
                include_testing=include_testing
            )
        else:
            schedule_df = fastf1_client.get_event_schedule(
                year=year,
                include_testing=include_testing
            )
    
        # Convert to list of dicts
        events_data = schedule_df.to_dict('records')
    
        # Apply round filter if specified
        if round is not None:
            events_data = [e for e in events_data if e.get('RoundNumber') == round]
    
        # Apply event name filter if specified
        if event_name is not None:
            events_data = [
                e for e in events_data
                if event_name.lower() in e.get('EventName', '').lower()
                or event_name.lower() in e.get('Country', '').lower()
                or event_name.lower() in e.get('Location', '').lower()
            ]
    
        # Convert to Pydantic models
        events_list = [_row_to_event_info(row) for row in events_data]
    
        return ScheduleResponse(
            year=year,
            total_events=len(events_list),
            include_testing=include_testing,
            events=events_list,
            round_filter=round,
            event_name_filter=event_name,
            only_remaining=only_remaining,
        )
  • Pydantic models EventInfo and ScheduleResponse defining the input/output structure for the get_schedule tool.
    class EventInfo(BaseModel):
        """Information about an F1 event (race weekend or testing)."""
    
        round_number: Optional[int] = Field(None, description="Round number in the championship")
        event_name: str = Field(..., description="Name of the event (e.g., 'Italian Grand Prix')")
        country: str = Field(..., description="Country where the event takes place")
        location: str = Field(..., description="City/location of the circuit")
        official_event_name: Optional[str] = Field(None, description="Full official event name")
        event_date: Optional[str] = Field(None, description="Main event date")
        event_format: Optional[str] = Field(None, description="Event format (conventional, sprint, testing)")
    
        # Session times
        session_1_date: Optional[str] = Field(None, description="Session 1 date and time")
        session_2_date: Optional[str] = Field(None, description="Session 2 date and time")
        session_3_date: Optional[str] = Field(None, description="Session 3 date and time")
        session_4_date: Optional[str] = Field(None, description="Session 4 date and time")
        session_5_date: Optional[str] = Field(None, description="Session 5 date and time")
    
        # Session names
        session_1_name: Optional[str] = Field(None, description="Session 1 name")
        session_2_name: Optional[str] = Field(None, description="Session 2 name")
        session_3_name: Optional[str] = Field(None, description="Session 3 name")
        session_4_name: Optional[str] = Field(None, description="Session 4 name")
        session_5_name: Optional[str] = Field(None, description="Session 5 name")
    
        # Testing event indicator
        is_testing: bool = Field(default=False, description="Whether this is a testing event")
    
    
    class ScheduleResponse(BaseModel):
        """Response containing F1 schedule information."""
    
        year: int = Field(..., description="Season year")
        total_events: int = Field(..., description="Total number of events")
        include_testing: bool = Field(..., description="Whether testing events are included")
        events: list[EventInfo] = Field(default_factory=list, description="List of events")
    
        # Optional filters applied
        round_filter: Optional[int] = Field(None, description="Round number filter (if applied)")
        event_name_filter: Optional[str] = Field(None, description="Event name filter (if applied)")
        only_remaining: bool = Field(default=False, description="Whether only remaining events are shown")
  • server.py:176-176 (registration)
    Registration of the get_schedule tool using the MCP @tool decorator.
    mcp.tool()(get_schedule)
  • Helper function that converts a pandas DataFrame row into an EventInfo Pydantic model, used within get_schedule.
    def _row_to_event_info(row) -> EventInfo:
        """Convert a DataFrame row to EventInfo pydantic model."""
        return EventInfo(
            round_number=int(row['RoundNumber']) if pd.notna(row.get('RoundNumber')) else None,
            event_name=str(row['EventName']) if pd.notna(row.get('EventName')) else "",
            country=str(row['Country']) if pd.notna(row.get('Country')) else "",
            location=str(row['Location']) if pd.notna(row.get('Location')) else "",
            official_event_name=str(row['OfficialEventName']) if pd.notna(row.get('OfficialEventName')) else None,
            event_date=str(row['EventDate']) if pd.notna(row.get('EventDate')) else None,
            event_format=str(row['EventFormat']) if pd.notna(row.get('EventFormat')) else None,
            session_1_date=str(row['Session1Date']) if pd.notna(row.get('Session1Date')) else None,
            session_2_date=str(row['Session2Date']) if pd.notna(row.get('Session2Date')) else None,
            session_3_date=str(row['Session3Date']) if pd.notna(row.get('Session3Date')) else None,
            session_4_date=str(row['Session4Date']) if pd.notna(row.get('Session4Date')) else None,
            session_5_date=str(row['Session5Date']) if pd.notna(row.get('Session5Date')) else None,
            session_1_name=str(row['Session1']) if pd.notna(row.get('Session1')) else None,
            session_2_name=str(row['Session2']) if pd.notna(row.get('Session2')) else None,
            session_3_name=str(row['Session3']) if pd.notna(row.get('Session3')) else None,
            session_4_name=str(row['Session4']) if pd.notna(row.get('Session4')) else None,
            session_5_name=str(row['Session5']) if pd.notna(row.get('Session5')) else None,
            is_testing=bool(row.get('EventFormat') == 'testing') if pd.notna(row.get('EventFormat')) else False,
        )

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