← All case studiesCase study · Race Engineer AI

A real-time AI race engineer for live iRacing sessions

A voice-driven AI race engineer for iRacing: the driver asks over push-to-talk and gets an F1-radio answer in under two seconds, grounded in live telemetry read through 19 MCP tools.

Stack
Python · asyncio · OpenAI · FastMCP · SQLite · Whisper
Latency
answers in under 2 s
Scale
19 MCP tools · 64 cars · 100 ms polling
The system

An LLM that answers a moving car in under two seconds

We built a production AI agent that acts as a real-time race engineer during live motorsport sessions. The driver speaks to it over push-to-talk: the voice is transcribed by Whisper, processed by an OpenAI agent with access to 19 live telemetry tools, and answered back via TTS in F1-radio style.

The agent sees lap times, tyre wear, fuel levels, competitor gaps, track flags and pit service status — all updated in real time from iRacing's SDK. The core engineering constraint sets the whole design: an LLM that must answer in under two seconds, working from data that is stale by definition, without hallucinating numbers it does not actually have.

Agent chat-flow sequence diagram: the driver's voice or text passes through race_engineer.py to the RaceEngineerAgent, which calls the OpenAI API and the MCP server against the iRacing SDK, keeps a sliding-window message history, and answers back via TTS.
Fig. 01The loop: push-to-talk → Whisper → OpenAI agent → 19 MCP tools → TTS reply.
MCP layer

Telemetry as a tool layer the agent can call

The telemetry layer is exposed to the agent through FastMCP — a server implementing the Model Context Protocol with 19 structured tools across six categories: raw telemetry values, session info, leaderboard, flags, pit commands, and lap statistics. The MCP client converts tool schemas automatically from MCP's JSON Schema into OpenAI function-calling definitions, so there is no manual mapping to keep in sync.

The agent decides which tools to call, and in which order, from the driver's question. "Should I pit this lap?" triggers get_current_pit_service_status, get_car_average_lap_time, get_leaderboard and get_my_car_damage_report in a single reasoning loop before it answers. MCP runs as a separate process over stdio — clean process isolation, no shared-memory race conditions between the agent and the live data feed. The same wiring applies to a CRM, an ERP or a ticketing system: we wrote up how to connect AI agents to your data without handing the model a copy of it.

The FastMCP server exposing 19 tools across six categories — raw telemetry, session info, leaderboard, status and flags, pit commands, and player/worker — all routed through one ExtendedTelemetryFacade to the live iRacing SDK.
Fig. 02The FastMCP server: 19 tools across six categories, all resolved through one ExtendedTelemetryFacade to the live iRacing SDK.
What broke

A lap time from 30 seconds ago is already wrong

The obvious approach — keep the full tool-call chain in conversation history — poisons the next question: the agent reasons from a lap time that was captured 30 seconds ago and is already wrong. Stale data carried forward is worse than no data.

The fix is a sliding window. Only the driver's question and the agent's final text response are persisted (MAX_HISTORY = 4); every intermediate tool call runs fresh each turn and is then discarded, and the system prompt is pinned as the first message. Session state lives separately: a TelemetryWorker polls iRacing at 100 ms intervals and writes completed laps for all 64 cars into SQLite — historical lap data without bloating the LLM context.

Live retrieval

RAG over live structured data, with a gate on pit commands

Instead of a vector store, the system does real-time structured retrieval through the MCP tools. Before every response it fetches the relevant data fresh: lap history from SQLite, a live telemetry snapshot from the iRacing SDK, and session standings from the in-memory leaderboard. An ExtendedTelemetryFacade acts as retrieval middleware — it hides the data sources behind one interface and decides whether to read from the live SDK, the lap database, or the snapshot. It is the same pattern as RAG over documents — retrieve at query time, inject, discard — applied to structured real-time data instead of text chunks.

Reading is autonomous; acting is not. High-risk pit commands pass through a human-in-the-loop gate before execution — the agent can recommend and prepare a stop, but the driver confirms it before anything is sent to the car.

Free process audit

See what this would look like in your operations.

Get in touch

30 minutes · we map your 3 best automation opportunities · no obligation