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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearYesSeason year
data_typeYesType: 'circuit_info' or 'track_status'
event_nameYesEvent name
session_nameNoSession name (if session-specific)
track_statusNoTrack status changes during session
circuit_detailsNoCircuit layout and corner information

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

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

With no annotations provided, the description carries full burden. It clarifies the tool returns either circuit details or track status changes, but doesn't disclose behavioral aspects like rate limits, authentication needs, error conditions, or whether this is a read-only operation. The examples help but don't fully compensate for missing behavioral context.

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

Conciseness4/5

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

Well-structured with clear sections (Args, Returns, Examples). The description is appropriately sized with no redundant information. Every sentence adds value, though the formatting with quotes and line breaks could be slightly cleaner.

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 4 parameters with 0% schema coverage and no annotations, the description does an excellent job explaining parameter semantics and usage. The presence of an output schema means return values don't need explanation. The main gap is lack of behavioral context (rate limits, auth, errors) which would be helpful for a data retrieval tool.

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

Parameters4/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 successfully explains all 4 parameters: year (season year 2018+), gp (Grand Prix name or round), data_type (with enum values explained), and session (required for track_status with session types listed). The description adds substantial meaning beyond the bare schema.

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 retrieves circuit layout, corners, or track status (flags, safety car) with specific verb+resource combinations. It distinguishes itself from siblings like get_session_details or get_track_evolution by focusing specifically on circuit data rather than session-specific or evolution data.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use each data_type option: 'circuit_info' for layout/corners and 'track_status' for flags. It also specifies that session parameter is required for track_status but not for circuit_info, offering clear conditional usage rules.

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