Skip to main content
Glama
MAKaminski

Home Depot MCP Server

by MAKaminski
newsIntelligence.ts11 kB
import axios from 'axios'; import { CONFIG } from '../config.js'; // Cache for news data const cache = new Map<string, { data: any; timestamp: number }>(); function getCachedData(key: string): any | null { const cached = cache.get(key); if (cached && Date.now() - cached.timestamp < CONFIG.DEFAULTS.CACHE_DURATION_MINUTES * 60 * 1000) { return cached.data; } return null; } function setCachedData(key: string, data: any): void { cache.set(key, { data, timestamp: Date.now() }); } export class NewsIntelligenceService { // Get comprehensive news analysis async getNewsAnalysis(query: string = 'Home Depot', days: number = 30) { const cacheKey = `news_${query}_${days}`; const cached = getCachedData(cacheKey); if (cached) return cached; try { const [newsApi, marketWatch, seekingAlpha] = await Promise.all([ this.getNewsAPIData(query, days), this.getMarketWatchData(), this.getSeekingAlphaData() ]); const newsData = { query, period: `${days} days`, sources: { newsApi, marketWatch, seekingAlpha }, sentiment: this.analyzeSentiment([newsApi, marketWatch, seekingAlpha]), summary: this.generateNewsSummary([newsApi, marketWatch, seekingAlpha]), timestamp: new Date().toISOString() }; setCachedData(cacheKey, newsData); return newsData; } catch (error) { throw new Error(`Failed to fetch news analysis: ${error}`); } } // Get NewsAPI data private async getNewsAPIData(query: string, days: number) { try { const fromDate = new Date(); fromDate.setDate(fromDate.getDate() - days); const response = await axios.get(CONFIG.DATA_SOURCES.NEWS.NEWS_API, { params: { q: query, from: fromDate.toISOString().split('T')[0], sortBy: 'publishedAt', language: 'en', apiKey: CONFIG.API_KEYS.NEWS_API } }); if (response.data.status === 'error') { throw new Error(response.data.message); } return { source: 'NewsAPI', totalResults: response.data.totalResults, articles: response.data.articles.slice(0, 10).map((article: any) => ({ title: article.title, description: article.description, url: article.url, publishedAt: article.publishedAt, source: article.source.name, sentiment: this.analyzeArticleSentiment(article.title + ' ' + article.description) })) }; } catch (error) { console.error('NewsAPI error:', error); return { source: 'NewsAPI', totalResults: 0, articles: [], error: error instanceof Error ? error.message : String(error) }; } } // Get MarketWatch data private async getMarketWatchData() { try { const response = await axios.get(CONFIG.DATA_SOURCES.NEWS.MARKETWATCH, { headers: { 'User-Agent': CONFIG.USER_AGENT } }); // Parse MarketWatch HTML for news const newsItems = this.parseMarketWatchNews(response.data); return { source: 'MarketWatch', totalResults: newsItems.length, articles: newsItems.map((item: any) => ({ title: item.title, description: item.description, url: item.url, publishedAt: item.publishedAt, source: 'MarketWatch', sentiment: this.analyzeArticleSentiment(item.title + ' ' + item.description) })) }; } catch (error) { console.error('MarketWatch error:', error); return { source: 'MarketWatch', totalResults: 0, articles: [], error: error instanceof Error ? error.message : String(error) }; } } // Get Seeking Alpha data private async getSeekingAlphaData() { try { const response = await axios.get(CONFIG.DATA_SOURCES.NEWS.SEEKING_ALPHA, { headers: { 'User-Agent': CONFIG.USER_AGENT } }); // Parse Seeking Alpha HTML for news const newsItems = this.parseSeekingAlphaNews(response.data); return { source: 'Seeking Alpha', totalResults: newsItems.length, articles: newsItems.map((item: any) => ({ title: item.title, description: item.description, url: item.url, publishedAt: item.publishedAt, source: 'Seeking Alpha', sentiment: this.analyzeArticleSentiment(item.title + ' ' + item.description) })) }; } catch (error) { console.error('Seeking Alpha error:', error); return { source: 'Seeking Alpha', totalResults: 0, articles: [], error: error instanceof Error ? error.message : String(error) }; } } // Parse MarketWatch news from HTML private parseMarketWatchNews(html: string) { const newsItems = []; // Simple regex-based parsing (in production, use proper HTML parsing) const newsRegex = /<h3[^>]*>([^<]+)<\/h3>/g; let match; while ((match = newsRegex.exec(html)) !== null) { if (match[1].includes('Home Depot') || match[1].includes('HD')) { newsItems.push({ title: match[1].trim(), description: 'MarketWatch news item', url: '#', publishedAt: new Date().toISOString() }); } } return newsItems.slice(0, 5); // Limit to 5 items } // Parse Seeking Alpha news from HTML private parseSeekingAlphaNews(html: string) { const newsItems = []; // Simple regex-based parsing const newsRegex = /<a[^>]*class="[^"]*sa-article[^"]*"[^>]*>([^<]+)<\/a>/g; let match; while ((match = newsRegex.exec(html)) !== null) { if (match[1].includes('Home Depot') || match[1].includes('HD')) { newsItems.push({ title: match[1].trim(), description: 'Seeking Alpha analysis', url: '#', publishedAt: new Date().toISOString() }); } } return newsItems.slice(0, 5); // Limit to 5 items } // Analyze sentiment of individual articles private analyzeArticleSentiment(text: string): 'positive' | 'negative' | 'neutral' { const positiveWords = ['growth', 'profit', 'increase', 'positive', 'strong', 'beat', 'exceed', 'up', 'gain', 'rise']; const negativeWords = ['decline', 'loss', 'decrease', 'negative', 'weak', 'miss', 'fall', 'down', 'drop', 'risk']; const lowerText = text.toLowerCase(); let positiveScore = 0; let negativeScore = 0; positiveWords.forEach(word => { if (lowerText.includes(word)) positiveScore++; }); negativeWords.forEach(word => { if (lowerText.includes(word)) negativeScore++; }); if (positiveScore > negativeScore) return 'positive'; if (negativeScore > positiveScore) return 'negative'; return 'neutral'; } // Analyze overall sentiment private analyzeSentiment(newsSources: any[]) { let totalPositive = 0; let totalNegative = 0; let totalNeutral = 0; let totalArticles = 0; newsSources.forEach(source => { if (source.articles) { source.articles.forEach((article: any) => { totalArticles++; switch (article.sentiment) { case 'positive': totalPositive++; break; case 'negative': totalNegative++; break; case 'neutral': totalNeutral++; break; } }); } }); const total = totalPositive + totalNegative + totalNeutral; if (total === 0) return { overall: 'neutral', scores: { positive: 0, negative: 0, neutral: 0 } }; return { overall: totalPositive > totalNegative ? 'positive' : totalNegative > totalPositive ? 'negative' : 'neutral', scores: { positive: Math.round((totalPositive / total) * 100), negative: Math.round((totalNegative / total) * 100), neutral: Math.round((totalNeutral / total) * 100) } }; } // Generate news summary private generateNewsSummary(newsSources: any[]) { const allArticles = newsSources.flatMap(source => source.articles || []); if (allArticles.length === 0) { return 'No recent news articles found.'; } const positiveArticles = allArticles.filter(article => article.sentiment === 'positive'); const negativeArticles = allArticles.filter(article => article.sentiment === 'negative'); const neutralArticles = allArticles.filter(article => article.sentiment === 'neutral'); return { totalArticles: allArticles.length, sentimentBreakdown: { positive: positiveArticles.length, negative: negativeArticles.length, neutral: neutralArticles.length }, keyThemes: this.extractKeyThemes(allArticles), summary: `Found ${allArticles.length} recent articles with ${positiveArticles.length} positive, ${negativeArticles.length} negative, and ${neutralArticles.length} neutral sentiment.` }; } // Extract key themes from articles private extractKeyThemes(articles: any[]) { const themes = new Map<string, number>(); articles.forEach(article => { const text = (article.title + ' ' + article.description).toLowerCase(); // Define key themes relevant to Home Depot const keyThemes = [ 'earnings', 'revenue', 'growth', 'dividend', 'stock', 'market', 'housing', 'construction', 'retail', 'consumer', 'economy', 'inflation', 'interest rates', 'supply chain', 'inventory' ]; keyThemes.forEach(theme => { if (text.includes(theme)) { themes.set(theme, (themes.get(theme) || 0) + 1); } }); }); // Return top themes return Array.from(themes.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 5) .map(([theme, count]) => ({ theme, count })); } // Get analyst ratings and recommendations async getAnalystRatings() { const cacheKey = 'analyst_ratings'; const cached = getCachedData(cacheKey); if (cached) return cached; try { // This would typically come from a financial data API // For now, providing mock data structure const ratings = { source: 'Analyst Consensus', timestamp: new Date().toISOString(), summary: { buy: 15, hold: 8, sell: 2, total: 25 }, consensus: 'Buy', priceTarget: { current: 350.00, target: 385.00, upside: 10.0 }, ratings: [ { firm: 'Goldman Sachs', rating: 'Buy', target: 400, date: '2024-01-15' }, { firm: 'Morgan Stanley', rating: 'Hold', target: 360, date: '2024-01-10' }, { firm: 'JP Morgan', rating: 'Buy', target: 390, date: '2024-01-08' } ] }; setCachedData(cacheKey, ratings); return ratings; } catch (error) { throw new Error(`Failed to fetch analyst ratings: ${error}`); } } }

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/MAKaminski/depot-mcp'

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