get_f1_news
Retrieve recent Formula 1 news from 25+ authoritative sources to stay updated on current race weekends, driver announcements, and technical developments within the past few weeks.
Instructions
PRIMARY TOOL for RECENT Formula 1 news from 25+ authoritative F1 sources via RSS feeds.
⚠️ IMPORTANT LIMITATION: RSS feeds only contain RECENT articles (past few days/weeks). This tool CANNOT retrieve historical news from months or years ago (e.g., 2013, 2020, etc.).
For historical F1 news (older than ~2 months), use web search instead.
USE THIS TOOL FOR:
✅ Latest breaking F1 news and updates
✅ Current race weekend coverage
✅ Recent driver/team announcements (within past few weeks)
✅ Current season news filtering by driver, team, circuit
✅ Technical developments and regulations from recent weeks
DO NOT use this tool for:
❌ Historical news from past years (e.g., "2013 Indian GP", "2020 season")
❌ News older than ~2 months
❌ Historical race coverage or archived articles
Available Sources (25+ RSS Feeds):
Official Sources:
"formula1" - Official Formula 1 website
"fia" - FIA press releases
Major Outlets:
"autosport" - Autosport F1
"motorsport" - Motorsport.com F1
"the-race" - The Race
"racefans" - RaceFans.net
"planetf1" - PlanetF1
"crash" - Crash.net F1
"grandprix" - GrandPrix.com
"espnf1" - ESPN F1
"skysportsf1" - Sky Sports F1
Specialist & Technical:
"f1technical" - F1Technical.net
"pitpass" - Pitpass
"joe-saward" - Joe Saward's F1 Blog
"racecar-engineering" - Racecar Engineering
Regional & International:
"gpblog" - GPBlog (Dutch/English)
"f1i" - F1i.com
"f1-insider-de" - F1 Insider (German)
"formel1-de" - Formel1.de (German)
Community & Fan Sources:
"wtf1" - WTF1
"racingnews365" - RacingNews365
"formulanerds" - Formula Nerds
"f1destinations" - F1 Destinations
"gpfans" - GPFans
"motorsportweek" - Motorsport Week
"racedepartment" - Race Department
Args: source: Specific source or "all" (default) - see full list above limit: Maximum articles to return, 1-100 (default: 10) keywords: General search keywords (searches in title and summary) driver: Filter by driver name (e.g., "Verstappen", "Hamilton", "Leclerc") team: Filter by team/constructor name (e.g., "Red Bull", "Ferrari", "Mercedes") circuit: Filter by circuit/track name (e.g., "Monaco", "Silverstone", "Spa") year: Filter by year (e.g., 2024) - NOTE: Only works for current/recent articles in feed date_from: Start date "YYYY-MM-DD" or "YYYY-MM" (optional) date_to: End date "YYYY-MM-DD" or "YYYY-MM" (optional)
Returns: NewsResponse with articles including titles, links, publication dates, summaries, and source names. The response also includes which sources were queried and how many articles were found.
Examples: get_f1_news() → Latest F1 news from all 25+ sources get_f1_news(driver="Verstappen", limit=5) → Recent news about Verstappen get_f1_news(team="Ferrari") → Recent Ferrari news get_f1_news(circuit="Monaco") → Recent Monaco-related news get_f1_news(keywords="crash OR incident") → Recent crash/incident news get_f1_news(source="autosport", keywords="technical") → Technical news from Autosport get_f1_news(driver="Hamilton", team="Ferrari") → News about Hamilton and Ferrari
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source | No | all | |
| limit | No | ||
| keywords | No | ||
| driver | No | ||
| team | No | ||
| circuit | No | ||
| year | No | ||
| date_from | No | ||
| date_to | No |
Implementation Reference
- tools/media/news.py:10-218 (handler)Main handler function implementing get_f1_news tool logic. Fetches recent F1 news from RSS feeds using RSSClient, applies flexible filters (source, limit, keywords, driver, team, circuit, year, date range), performs client-side filtering and sorting, and returns structured NewsResponse.def get_f1_news( source: str = "all", limit: int = 10, keywords: Optional[str] = None, driver: Optional[str] = None, team: Optional[str] = None, circuit: Optional[str] = None, year: Optional[int] = None, date_from: Optional[str] = None, date_to: Optional[str] = None ) -> NewsResponse: """ **PRIMARY TOOL** for RECENT Formula 1 news from 25+ authoritative F1 sources via RSS feeds. ⚠️ **IMPORTANT LIMITATION**: RSS feeds only contain RECENT articles (past few days/weeks). This tool CANNOT retrieve historical news from months or years ago (e.g., 2013, 2020, etc.). **For historical F1 news (older than ~2 months), use web search instead.** **USE THIS TOOL FOR:** - ✅ Latest breaking F1 news and updates - ✅ Current race weekend coverage - ✅ Recent driver/team announcements (within past few weeks) - ✅ Current season news filtering by driver, team, circuit - ✅ Technical developments and regulations from recent weeks **DO NOT use this tool for:** - ❌ Historical news from past years (e.g., "2013 Indian GP", "2020 season") - ❌ News older than ~2 months - ❌ Historical race coverage or archived articles **Available Sources (25+ RSS Feeds):** Official Sources: - "formula1" - Official Formula 1 website - "fia" - FIA press releases Major Outlets: - "autosport" - Autosport F1 - "motorsport" - Motorsport.com F1 - "the-race" - The Race - "racefans" - RaceFans.net - "planetf1" - PlanetF1 - "crash" - Crash.net F1 - "grandprix" - GrandPrix.com - "espnf1" - ESPN F1 - "skysportsf1" - Sky Sports F1 Specialist & Technical: - "f1technical" - F1Technical.net - "pitpass" - Pitpass - "joe-saward" - Joe Saward's F1 Blog - "racecar-engineering" - Racecar Engineering Regional & International: - "gpblog" - GPBlog (Dutch/English) - "f1i" - F1i.com - "f1-insider-de" - F1 Insider (German) - "formel1-de" - Formel1.de (German) Community & Fan Sources: - "wtf1" - WTF1 - "racingnews365" - RacingNews365 - "formulanerds" - Formula Nerds - "f1destinations" - F1 Destinations - "gpfans" - GPFans - "motorsportweek" - Motorsport Week - "racedepartment" - Race Department Args: source: Specific source or "all" (default) - see full list above limit: Maximum articles to return, 1-100 (default: 10) keywords: General search keywords (searches in title and summary) driver: Filter by driver name (e.g., "Verstappen", "Hamilton", "Leclerc") team: Filter by team/constructor name (e.g., "Red Bull", "Ferrari", "Mercedes") circuit: Filter by circuit/track name (e.g., "Monaco", "Silverstone", "Spa") year: Filter by year (e.g., 2024) - NOTE: Only works for current/recent articles in feed date_from: Start date "YYYY-MM-DD" or "YYYY-MM" (optional) date_to: End date "YYYY-MM-DD" or "YYYY-MM" (optional) Returns: NewsResponse with articles including titles, links, publication dates, summaries, and source names. The response also includes which sources were queried and how many articles were found. Examples: get_f1_news() → Latest F1 news from all 25+ sources get_f1_news(driver="Verstappen", limit=5) → Recent news about Verstappen get_f1_news(team="Ferrari") → Recent Ferrari news get_f1_news(circuit="Monaco") → Recent Monaco-related news get_f1_news(keywords="crash OR incident") → Recent crash/incident news get_f1_news(source="autosport", keywords="technical") → Technical news from Autosport get_f1_news(driver="Hamilton", team="Ferrari") → News about Hamilton and Ferrari """ # Validate limit if not 1 <= limit <= 100: raise ValueError("Limit must be between 1 and 100") # Determine fetch limit: fetch more if filtering is applied has_filters = any([keywords, driver, team, circuit, year, date_from, date_to]) fetch_limit = min(limit * 3, 100) if has_filters else limit # Fetch news from source(s) news_response = rss_client.get_news(source=source, limit=fetch_limit) filtered_articles = news_response.articles # Apply driver filtering if driver: driver_lower = driver.lower() filtered_articles = [ article for article in filtered_articles if driver_lower in article.title.lower() or driver_lower in article.summary.lower() ] # Apply team filtering if team: team_lower = team.lower() filtered_articles = [ article for article in filtered_articles if team_lower in article.title.lower() or team_lower in article.summary.lower() ] # Apply circuit filtering if circuit: circuit_lower = circuit.lower() # Also check for common variations (e.g., "Monaco" matches "Monaco GP", "Circuit de Monaco") filtered_articles = [ article for article in filtered_articles if circuit_lower in article.title.lower() or circuit_lower in article.summary.lower() ] # Apply keyword filtering if keywords: keywords_lower = keywords.lower() # Support OR operator for multiple keywords if " or " in keywords_lower: keyword_list = [kw.strip() for kw in keywords_lower.split(" or ")] filtered_articles = [ article for article in filtered_articles if any(kw in article.title.lower() or kw in article.summary.lower() for kw in keyword_list) ] else: # Single keyword or phrase filtered_articles = [ article for article in filtered_articles if keywords_lower in article.title.lower() or keywords_lower in article.summary.lower() ] # Apply date filtering # Convert year to date_from/date_to if specified if year: if not date_from: date_from = f"{year}-01-01" if not date_to: date_to = f"{year}-12-31" if date_from or date_to: date_filtered = [] for article in filtered_articles: try: # Parse article date (handling various formats) article_date = datetime.fromisoformat(article.published.replace('Z', '+00:00')) article_date_str = article_date.strftime("%Y-%m-%d") # Support month-only filtering (YYYY-MM format) if date_from: compare_from = date_from if len(date_from) > 7 else f"{date_from}-01" if article_date_str < compare_from: continue if date_to: # If month format, get last day of month if len(date_to) == 7: # YYYY-MM format year_val = int(date_to.split('-')[0]) month_val = int(date_to.split('-')[1]) # Get last day of month if month_val == 12: compare_to = f"{year_val}-12-31" else: next_month = datetime(year_val, month_val + 1, 1) last_day = (next_month - timedelta(days=1)).day compare_to = f"{year_val}-{month_val:02d}-{last_day}" else: compare_to = date_to if article_date_str > compare_to: continue date_filtered.append(article) except Exception: # If date parsing fails, include the article date_filtered.append(article) filtered_articles = date_filtered # Limit results filtered_articles = filtered_articles[:limit] # Return response return NewsResponse( source=source, fetched_at=datetime.now().isoformat(), article_count=len(filtered_articles), articles=filtered_articles )
- Pydantic model defining the output schema for get_f1_news tool. Includes source, fetch time, count, and list of NewsArticle objects.class NewsResponse(BaseModel): """Collection of F1 news articles.""" source: str = Field(..., description="News source(s) queried") fetched_at: str = Field(..., description="When the feed was fetched") article_count: int = Field(..., description="Number of articles returned") articles: list[NewsArticle] = Field(..., description="List of news articles")
- server.py:180-180 (registration)MCP tool registration for get_f1_news using the FastMCP decorator.mcp.tool()(get_f1_news)
- clients/rss_client.py:63-94 (helper)Core helper method in RSSClient that fetches news from single or all RSS feeds (25+ F1 sources), parses feedparser entries into NewsArticle models, and constructs NewsResponse. Used directly by the handler.def get_news(self, source: str, limit: int) -> NewsResponse: """ Fetch F1 news from RSS feeds. Args: source: News source identifier or "all" limit: Maximum articles to return Returns: NewsResponse: Structured news data Raises: ValueError: If source is invalid RuntimeError: If feed fetch fails """ # Validate source if source != "all" and source not in self.RSS_FEEDS: valid_sources = ", ".join(self.RSS_FEEDS.keys()) raise ValueError( f"Invalid source '{source}'. Must be one of: {valid_sources}, all" ) try: if source == "all": return self._fetch_all_sources(limit) else: return self._fetch_single_source(source, limit) except ValueError: raise except Exception as e: raise RuntimeError(f"Failed to fetch news from {source}: {str(e)}")
- clients/rss_client.py:19-57 (helper)Dictionary of 25+ RSS feed URLs for F1 news sources, used by RSSClient to aggregate news from official, major outlets, specialist, and fan sites.RSS_FEEDS = { # Official sources "formula1": "https://www.formula1.com/content/fom-website/en/latest/all.xml", "fia": "https://www.fia.com/rss/press-release", # Major F1 news outlets "autosport": "https://www.autosport.com/rss/feed/f1", "motorsport": "https://www.motorsport.com/rss/f1/news/", "the-race": "https://the-race.com/formula-1/feed/", "racefans": "https://www.racefans.net/feed/", "planetf1": "https://www.planetf1.com/feed/", "crash": "https://www.crash.net/rss/f1/news/1", "grandprix": "https://www.grandprix.com/feed/", "espnf1": "https://www.espn.com/espn/rss/rpm/news", "skysportsf1": "https://www.skysports.com/rss/12040", # Specialist & Technical sources "f1technical": "https://www.f1technical.net/rss/news.xml", "pitpass": "https://www.pitpass.com/rss", "joe-saward": "https://joesaward.wordpress.com/feed/", "racecar-engineering": "https://www.racecar-engineering.com/feed/", # Regional & International sources "gpblog": "https://www.gpblog.com/en/rss.xml", "f1i": "https://f1i.com/feed", "f1-insider-de": "https://www.f1-insider.com/feed/", "formel1-de": "https://www.formel1.de/rss.xml", # Community & Fan sources "wtf1": "https://wtf1.com/feed/", "racingnews365": "https://racingnews365.com/rss", "formulanerds": "https://formulanerds.com/feed/", "f1destinations": "https://f1destinations.com/feed/", "gpfans": "https://www.gpfans.com/en/rss.xml", # Additional coverage "motorsportweek": "https://www.motorsportweek.com/feed/", "racedepartment": "https://www.racedepartment.com/forums/f1-2021-the-game.214/index.rss", }