Skip to main content
Glama

get_circuit

Retrieve Formula 1 circuit layouts, corner details, or real-time track status including flags and safety car periods for specific Grand Prix events.

Instructions

Get circuit layout, corners, or track status (flags, safety car).

Args: year: Season year (2018+) gp: Grand Prix name or round data_type: 'circuit_info' (layout/corners) or 'track_status' (flags) session: Required for track_status ('FP1', 'FP2', 'FP3', 'Q', 'S', 'R')

Returns: CircuitDataResponse with circuit details or track status changes

Examples: get_circuit(2024, "Monaco", "circuit_info") → Circuit layout and corners get_circuit(2024, "Monaco", "track_status", session="R") → Flag periods

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearYes
gpYes
data_typeNocircuit_info
sessionNo

Implementation Reference

  • Main handler function implementing the get_circuit tool logic. Fetches circuit layout, corners, and track status data using FastF1 client.
    def get_circuit(
        year: int,
        gp: Union[str, int],
        data_type: Literal["circuit_info", "track_status"] = "circuit_info",
        session: Optional[str] = None,
    ) -> CircuitDataResponse:
        """
        Get circuit layout, corners, or track status (flags, safety car).
    
        Args:
            year: Season year (2018+)
            gp: Grand Prix name or round
            data_type: 'circuit_info' (layout/corners) or 'track_status' (flags)
            session: Required for track_status ('FP1', 'FP2', 'FP3', 'Q', 'S', 'R')
    
        Returns:
            CircuitDataResponse with circuit details or track status changes
    
        Examples:
            get_circuit(2024, "Monaco", "circuit_info") → Circuit layout and corners
            get_circuit(2024, "Monaco", "track_status", session="R") → Flag periods
        """
        # Get event information
        event = fastf1_client.get_event(year, gp)
    
        if data_type == "circuit_info":
            # Load a session to get circuit info (use Race or first available session)
            if session:
                session_obj = fastf1_client.get_session(year, gp, session)
            else:
                # Try to get race session, fallback to any available
                try:
                    session_obj = fastf1_client.get_session(year, gp, 'R')
                except Exception:
                    try:
                        session_obj = fastf1_client.get_session(year, gp, 'Q')
                    except Exception:
                        session_obj = fastf1_client.get_session(year, gp, 1)
    
            session_obj.load()
    
            # Get circuit information
            try:
                circuit_info = session_obj.get_circuit_info()
    
                # Extract corner information
                corners_list = []
                if circuit_info.corners is not None and len(circuit_info.corners) > 0:
                    for idx, corner in circuit_info.corners.iterrows():
                        corners_list.append(
                            CornerInfo(
                                number=int(corner['Number']) if pd.notna(corner.get('Number')) else idx,
                                letter=str(corner['Letter']) if pd.notna(corner.get('Letter')) else None,
                                distance=float(corner['Distance']) if pd.notna(corner.get('Distance')) else None,
                                x=float(corner['X']) if pd.notna(corner.get('X')) else None,
                                y=float(corner['Y']) if pd.notna(corner.get('Y')) else None,
                            )
                        )
    
                circuit_details = CircuitDetails(
                    circuit_key=int(circuit_info.circuit_key) if hasattr(circuit_info, 'circuit_key') and circuit_info.circuit_key else None,
                    circuit_name=str(event['EventName']) if event is not None else None,
                    location=str(event['Location']) if event is not None else None,
                    country=str(event['Country']) if event is not None else None,
                    rotation=float(circuit_info.rotation) if hasattr(circuit_info, 'rotation') and circuit_info.rotation else None,
                    corners=corners_list if corners_list else None,
                )
            except Exception as e:
                # If circuit info not available, provide basic event info
                circuit_details = CircuitDetails(
                    circuit_name=str(event['EventName']) if event is not None else None,
                    location=str(event['Location']) if event is not None else None,
                    country=str(event['Country']) if event is not None else None,
                )
    
            return CircuitDataResponse(
                year=year,
                event_name=str(event['EventName']) if event is not None else "",
                session_name=None,
                circuit_details=circuit_details,
                data_type=data_type,
            )
    
        elif data_type == "track_status":
            if not session:
                raise ValueError("session parameter is required for track_status data type")
    
            # Load session with track status data
            session_obj = fastf1_client.get_session(year, gp, session)
            session_obj.load()
    
            # Get track status data
            track_status_df = session_obj.track_status
            track_status_list = []
    
            if track_status_df is not None and len(track_status_df) > 0:
                for idx, row in track_status_df.iterrows():
                    # Map status codes to messages
                    status_code = str(row['Status'])
                    status_messages = {
                        '1': 'Green Flag / Track Clear',
                        '2': 'Yellow Flag / Caution',
                        '3': 'Green Flag (after SC)',
                        '4': 'Safety Car',
                        '5': 'Red Flag / Session Stopped',
                        '6': 'Virtual Safety Car (VSC)',
                        '7': 'VSC Ending',
                    }
                    message = status_messages.get(status_code, f'Status Code {status_code}')
    
                    track_status_list.append(
                        TrackStatusInfo(
                            time=str(row['Time']) if pd.notna(row.get('Time')) else "",
                            status=status_code,
                            message=message,
                        )
                    )
    
            return CircuitDataResponse(
                year=year,
                event_name=str(event['EventName']) if event is not None else "",
                session_name=session_obj.name if hasattr(session_obj, 'name') else session,
                track_status=track_status_list,
                data_type=data_type,
            )
  • Pydantic BaseModel definitions for the tool's input parameters (via function signature) and output response (CircuitDataResponse and supporting models).
    from pydantic import BaseModel, Field
    from typing import Optional
    
    
    class CornerInfo(BaseModel):
        """Information about a corner on the circuit."""
    
        number: int = Field(..., description="Corner number")
        letter: Optional[str] = Field(None, description="Corner letter (if applicable)")
        distance: Optional[float] = Field(None, description="Distance from start line in meters")
        x: Optional[float] = Field(None, description="X coordinate")
        y: Optional[float] = Field(None, description="Y coordinate")
    
    
    class CircuitDetails(BaseModel):
        """Detailed circuit information."""
    
        circuit_key: Optional[int] = Field(None, description="Circuit key/ID")
        circuit_name: Optional[str] = Field(None, description="Circuit name")
        location: Optional[str] = Field(None, description="Circuit location")
        country: Optional[str] = Field(None, description="Country")
        rotation: Optional[float] = Field(None, description="Circuit rotation angle")
        corners: Optional[list[CornerInfo]] = Field(None, description="List of corners on the circuit")
    
    
    class TrackStatusInfo(BaseModel):
        """Track status information during a session."""
    
        time: str = Field(..., description="Time of status")
        status: str = Field(..., description="Track status code (1=Green, 2=Yellow, 4=SC, 5=Red, 6=VSC, 7=VSC Ending)")
        message: Optional[str] = Field(None, description="Human-readable status message")
    
    
    class CircuitDataResponse(BaseModel):
        """Response containing circuit and track information."""
    
        year: int = Field(..., description="Season year")
        event_name: str = Field(..., description="Event name")
        session_name: Optional[str] = Field(None, description="Session name (if session-specific)")
    
        # Circuit details
        circuit_details: Optional[CircuitDetails] = Field(None, description="Circuit layout and corner information")
    
        # Track status (session-specific)
        track_status: Optional[list[TrackStatusInfo]] = Field(None, description="Track status changes during session")
    
        # Metadata
        data_type: str = Field(..., description="Type: 'circuit_info' or 'track_status'")
  • server.py:165-165 (registration)
    Registration of the get_circuit tool using the FastMCP decorator mcp.tool().
    mcp.tool()(get_circuit)

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