Skip to main content
Glama

Formula One MCP Server

nlSynthesizer.ts6.01 kB
// Cursor-Grade Natural Language Synthesis for F1 Data // Transforms raw MCP tool returns into conversational responses export interface SynthesisStage { stage: 'extract' | 'summarize' | 'narrate'; input: any; output: string; } export class NLSynthesizer { /** * Stage 1: Extract - Flatten nested JSON → key metrics dict */ private extract(data: any): Record<string, any> { const flat: Record<string, any> = {}; if (!data) return flat; // Handle championship standings if (data.drivers && Array.isArray(data.drivers)) { flat.drivers = data.drivers.slice(0, 10); // Top 10 flat.constructors = data.constructors?.slice(0, 5); // Top 5 teams } // Handle event schedule if (Array.isArray(data) && data.length > 0) { flat.events = data.slice(0, 10); // First 10 events } // Handle driver performance if (data.DriverCode || data.TotalLaps || data.FastestLap) { flat.performance = { driver: data.DriverCode, totalLaps: data.TotalLaps, fastestLap: data.FastestLap, avgLapTime: data.AverageLapTime }; } // Handle session results if (Array.isArray(data) && data.length > 0 && data[0].position) { flat.results = data.slice(0, 10); // Top 10 finishers } return flat; } /** * Stage 2: Summarize - Generate bullet facts from extracted data */ private summarize(extracted: Record<string, any>): string { const facts: string[] = []; // Championship standings if (extracted.drivers) { const top3 = extracted.drivers.slice(0, 3); top3.forEach((driver: any) => { const ordinal = this.getOrdinal(parseInt(driver.position)); facts.push(`${ordinal} place: ${driver.givenName} ${driver.familyName} (${driver.driverCode}) with ${driver.points} points and ${driver.wins} wins`); }); if (extracted.constructors) { const topTeam = extracted.constructors[0]; facts.push(`Constructors champion: ${topTeam.constructorName} with ${topTeam.points} points`); } } // Event schedule if (extracted.events) { const firstEvent = extracted.events[0]; const lastEvent = extracted.events[extracted.events.length - 1]; facts.push(`Season runs from ${firstEvent.EventDate || firstEvent.eventDate} to ${lastEvent.EventDate || lastEvent.eventDate}`); facts.push(`Total of ${extracted.events.length} Grand Prix events`); } // Driver performance if (extracted.performance) { const perf = extracted.performance; if (perf.totalLaps) facts.push(`Completed ${perf.totalLaps} laps`); if (perf.fastestLap) { const formattedLapTime = this.formatLapTime(perf.fastestLap); facts.push(`Fastest lap: ${formattedLapTime}`); } if (perf.avgLapTime) facts.push(`Average lap time: ${perf.avgLapTime.toFixed(2)}s`); } // Session results if (extracted.results) { const winner = extracted.results[0]; facts.push(`Winner: ${winner.givenName} ${winner.familyName} (${winner.driverCode})`); if (winner.lapTime) facts.push(`Winning time: ${winner.lapTime}`); } return facts.join('. ') + '.'; } /** * Stage 3: Narrate - Create conversational wrap-up */ private narrate(query: string, facts: string): string { const queryLower = query.toLowerCase(); // Championship queries if (queryLower.includes('championship') || queryLower.includes('standings')) { if (queryLower.includes('vettel') || queryLower.includes('redbull') || queryLower.includes('red bull')) { return `🏆 ${facts}`; } return `📊 ${facts}`; } // Schedule queries if (queryLower.includes('schedule') || queryLower.includes('calendar')) { return `📅 ${facts}`; } // Performance queries if (queryLower.includes('performance') || queryLower.includes('stats')) { return `🏁 ${facts}`; } // Default return facts; } /** * Main synthesis method */ public synthesize(query: string, data: any): string { try { // Stage 1: Extract const extracted = this.extract(data); // Stage 2: Summarize const facts = this.summarize(extracted); // Stage 3: Narrate const narrative = this.narrate(query, facts); return narrative.trim(); } catch (error) { console.error('Synthesis error:', error); return `📊 Data retrieved successfully. ${JSON.stringify(data).substring(0, 100)}...`; } } /** * Helper: Convert numbers to ordinal names */ private getOrdinal(num: number): string { const ordinals = ['1st', '2nd', '3rd', '4th', '5th', '6th', '7th', '8th', '9th', '10th']; return ordinals[num - 1] || `${num}th`; } /** * Helper: Format time differences */ public formatDelta(seconds: number): string { if (seconds < 0) { return `${Math.abs(seconds).toFixed(3)} s slower`; } return `${seconds.toFixed(3)} s quicker`; } /** * Helper: Format lap time from timedelta string */ private formatLapTime(lapTime: string): string { // Handle pandas timedelta format like "0 days 00:00:45.754000" if (lapTime.includes('days')) { const match = lapTime.match(/(\d+) days (\d+):(\d+):(\d+\.\d+)/); if (match) { const [, days, hours, minutes, secondsAndMs] = match; const [seconds, milliseconds] = secondsAndMs.split('.'); const totalMinutes = parseInt(days) * 24 * 60 + parseInt(hours) * 60 + parseInt(minutes); const msFormatted = milliseconds ? milliseconds.substring(0, 3) : '000'; // Format as MM:SS.mmm (lap time format) return `${totalMinutes}:${seconds.padStart(2, '0')}.${msFormatted}`; } } // Handle other formats return lapTime; } } // Export singleton instance export const nlSynthesizer = new NLSynthesizer();

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/notsedano/f1-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server