Skip to main content
Glama
r-huijts

FirstCycling MCP Server

by r-huijts

get_rider_victories

Retrieve a detailed list of a cyclist's UCI-registered race victories, including race categories, dates, and years. Optionally filter results to display only WorldTour wins. Use rider ID to fetch data.

Instructions

Get a comprehensive list of a rider's UCI victories. This tool retrieves detailed information about all UCI-registered race victories achieved by the cyclist throughout their career. Victories can be filtered to show only WorldTour wins if desired.

Note: If you don't know the rider's ID, use the search_rider tool first to find it by name.

Example usage:
- Get all UCI victories for Tadej Pogačar (ID: 16973)
- Get WorldTour victories for Jonas Vingegaard (ID: 16974)

Returns a formatted string with:
- Complete list of victories
- Race details including category
- Date and year of each victory
- Option to filter by WorldTour races only

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
rider_idYes
world_tour_onlyNo

Implementation Reference

  • The handler function named get_rider_victories that implements the tool logic by fetching rider victories using the API and displaying summary statistics.
    def get_rider_victories(rider_id):
        """Get a rider's victories from FirstCycling"""
        rider = Rider(rider_id)
        
        # Get basic rider info
        print(f"Rider ID: {rider.ID}")
        
        # Get all victories
        victories = rider.victories()
        
        # Display information about victories
        if hasattr(victories, 'results_df') and not victories.results_df.empty:
            print(f"\nFound {len(victories.results_df)} career victories:")
            
            # Group by year to count victories per year
            victories_by_year = victories.results_df.groupby('Year').size()
            print("\nVictories by year:")
            for year, count in victories_by_year.items():
                print(f"{year}: {count} wins")
            
            # Check for specific race categories
            if 'CAT' in victories.results_df.columns:
                categories = victories.results_df['CAT'].value_counts()
                print("\nVictories by category:")
                for category, count in categories.items():
                    print(f"{category}: {count}")
                    
            # Display the first 10 victories
            print("\nMost recent 10 victories:")
            # Sort by date (newest first) and show the first 10
            if 'Date_Formatted' in victories.results_df.columns:
                recent_victories = victories.results_df.sort_values('Date_Formatted', ascending=False).head(10)
                # Display in a readable format
                for _, row in recent_victories.iterrows():
                    print(f"{row['Date_Formatted']}: {row['Race']} ({row['CAT']})")
        else:
            print("No victories found for this rider.")
  • Supporting method in Rider class to fetch the victories data by calling the RiderVictories endpoint.
    def victories(self, world_tour=None, uci=None):
    	"""
    	Get the rider's victories.
    
    	Parameters
    	----------
    	world_tour : bool
    		True if only World Tour wins wanted
    	uci : bool
    		True if only UCI wins wanted
    
    	Returns
    	-------
    	RiderVictories
    	"""
    	return self._get_endpoint(endpoint=RiderVictories, high=1, k=1, uci=1 if uci else None, wt=1 if world_tour else None)
  • The core parsing class for rider victories endpoint that extracts and formats the victories table into a pandas DataFrame.
    class RiderVictories(RiderEndpoint):
    	"""
    	Rider's victories. Extends RiderEndpoint.
    
    	Attributes
    	----------
    	results_df : pd.DataFrame
    		Table of rider's victories.
    	"""
    
    	def _parse_soup(self):
    		super()._parse_soup()
    		self._get_victories()
    
    	def _get_victories(self):
    		# Find table with victories
    		table = self.soup.find('table', {'class': "sortTabell tablesorter"})
    		if table:
    			# Check if the table has "No data" content
    			no_data_text = table.get_text().strip()
    			if "No data" in no_data_text:
    				# Table exists but has no data
    				self.results_df = pd.DataFrame()
    				return
    				
    			try:
    				# Try to parse using the parse_table function
    				self.results_df = parse_table(table)
    				if self.results_df is None:
    					self.results_df = pd.DataFrame()  # Empty DataFrame if no victories found
    			except Exception as e:
    				# If there's an error in parsing, handle it by creating a basic DataFrame manually
    				print(f"Warning: Error parsing victories table: {str(e)}")
    				# Fallback: Try to create a DataFrame directly from the HTML
    				try:
    					import io
    					from dateutil.parser import parse
    					
    					# Parse the basic table
    					html = str(table)
    					self.results_df = pd.read_html(io.StringIO(html), decimal=',')[0]
    					
    					# Check if the table contains "No data"
    					if (self.results_df.shape[0] == 1 and 
    						"No data" in self.results_df.iloc[0, 0]):
    						self.results_df = pd.DataFrame()
    						return
    					
    					# Clean up column names
    					# The typical format is: Year | Date | Race | Category
    					if 'Date.1' in self.results_df.columns:
    						self.results_df.rename(columns={
    							'Date': 'Year', 
    							'Date.1': 'Date',
    							'Unnamed: 2': 'Month_Day'  # This can be blank or contain additional date info
    						}, inplace=True)
    						
    						# Convert Year to string
    						self.results_df['Year'] = self.results_df['Year'].astype(str)
    						
    						# Handle date formatting - combine Year and Date if available
    						if 'Month_Day' in self.results_df.columns:
    							# Clean Month_Day column (keep only non-NaN values)
    							self.results_df = self.results_df.drop('Month_Day', axis=1)
    							
    						# If Date column has decimal format (e.g., 22.04), treat as MM.DD format
    						def format_date(row):
    							try:
    								if pd.notnull(row['Date']):
    									date_str = row['Date']
    									if isinstance(date_str, float):
    										# Convert float (22.04) to string and handle decimal
    										date_parts = str(date_str).split('.')
    										if len(date_parts) == 2:
    											day = date_parts[0].zfill(2)
    											month = date_parts[1].zfill(2)
    											return f"{row['Year']}-{month}-{day}"
    									return f"{row['Year']}-01-01"  # Default date if format not recognized
    								return f"{row['Year']}-01-01"  # Default date if no Date value
    							except:
    								return f"{row['Year']}-01-01"  # Default for any errors
    						
    						# Create formatted date column
    						self.results_df['Date_Formatted'] = self.results_df.apply(format_date, axis=1)
    				except Exception as e:
    					# If all else fails, just return an empty DataFrame
    					print(f"Warning: Error creating DataFrame from table HTML: {str(e)}")
    					self.results_df = pd.DataFrame()
    		else:
    			# No table found
    			self.results_df = pd.DataFrame()

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/r-huijts/firstcycling-mcp'

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