get_news
Retrieve news headlines for stock symbols to support trading decisions and portfolio monitoring with structured article data.
Instructions
Retrieves recent news headlines for a given symbol.
Args:
symbol: Ticker symbol.
max_items: Maximum number of news items to return.
Returns:
JSON string of news articles with titles and publishers.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | ||
| max_items | No |
Implementation Reference
- tools/news_intelligence.py:20-84 (handler)Main implementation of the get_news tool. Fetches recent news headlines for a given stock symbol primarily from yfinance.Ticker.news, with fallbacks to NewsAPI and Google News (GNews) if no results. Returns formatted JSON string of articles.def get_news(symbol: str, max_items: int = 10) -> str: """ Retrieves recent news headlines for a given symbol. Args: symbol: Ticker symbol. max_items: Maximum number of news items to return. Returns: JSON string of news articles with titles and publishers. """ try: ticker = yf.Ticker(symbol) news = ticker.news if not news: # Try NewsAPI first if available if NEWSAPI_KEY: logger.info(f"yfinance news empty for {symbol}, trying NewsAPI") newsapi_results = get_newsapi_articles(symbol, max_items) if newsapi_results: import json return json.dumps(newsapi_results, indent=2) # Fallback to Google News logger.info(f"Trying GNews fallback for {symbol}") gnews_results = get_google_news(symbol, max_items) if gnews_results: import json return json.dumps(gnews_results, indent=2) logger.warning(f"No news found for {symbol} from any source") return f"No news found for {symbol}" # Limit results news = news[:max_items] # Extract relevant fields (handle nested yfinance structure) results = [] for item in news: # yfinance returns nested structure with 'content' key content = item.get("content", item) # fallback to item if no content key title = content.get("title", "") # Publisher info is in 'provider' dict provider = content.get("provider", {}) publisher = provider.get("displayName", "") if isinstance(provider, dict) else item.get("publisher", "") link = content.get("canonicalUrl", {}).get("url", "") if not link: link = item.get("link", "") results.append({ "title": title, "publisher": publisher, "link": link, }) logger.info(f"Fetched {len(results)} news items for {symbol} from yfinance") import json return json.dumps(results, indent=2) except Exception as e: logger.error(f"Error fetching news for {symbol}: {e}", exc_info=True) return f"Error fetching news for {symbol}: {str(e)}"
- server.py:405-408 (registration)Registers the get_news tool (alongside analyze_sentiment and get_symbol_sentiment) to the FastMCP server instance using the register_tools helper function, which applies @mcp.tool() decorator.register_tools( [get_news, analyze_sentiment, get_symbol_sentiment], "News & Sentiment" )
- tools/news_intelligence.py:87-108 (helper)Helper function called by get_news as fallback: fetches news articles from Google News using GNews library.def get_google_news(symbol: str, max_items: int = 5) -> List[Dict]: """ Fetches news from Google News via GNews library. """ try: google_news = GNews(max_results=max_items) # Search for the symbol results = google_news.get_news(symbol) cleaned = [] for item in results: cleaned.append({ "title": item.get("title", ""), "publisher": item.get("publisher", {}).get("title", "Unknown"), "link": item.get("url", ""), "published": item.get("published date", "") }) return cleaned except Exception as e: logger.error(f"GNews error for {symbol}: {e}") return []
- tools/news_intelligence.py:110-144 (helper)Helper function called by get_news as primary fallback: fetches business news articles matching the symbol from NewsAPI.org.def get_newsapi_articles(symbol: str, max_items: int = 5) -> List[Dict]: """ Fetches news from NewsAPI.org using the company name or symbol. """ if not NEWSAPI_KEY: logger.warning("NewsAPI key not configured") return [] try: newsapi = NewsApiClient(api_key=NEWSAPI_KEY) # Search for the symbol (NewsAPI works better with company names, but symbols can work) # We'll search in business category for relevance response = newsapi.get_everything( q=symbol, language='en', sort_by='publishedAt', page_size=max_items ) articles = response.get('articles', []) cleaned = [] for article in articles: cleaned.append({ "title": article.get("title", ""), "publisher": article.get("source", {}).get("name", "Unknown"), "link": article.get("url", ""), "published": article.get("publishedAt", ""), "description": article.get("description", "") }) return cleaned except Exception as e: logger.error(f"NewsAPI error for {symbol}: {e}") return []
- server.py:19-19 (registration)Import statement bringing the get_news function into server.py for registration.from tools.news_intelligence import get_news, analyze_sentiment, get_symbol_sentiment