UNPKG

@iriseller/mcp-server

Version:

Model Context Protocol (MCP) server providing access to IRISeller's AI sales intelligence platform with 7 AI agents, multi-CRM integration, advanced sales workflows, email automation, Rosa demo functionality with action scoring, DNC compliance checking, G

229 lines (228 loc) 9.63 kB
import { WebSearchService } from './web-search-service.js'; export class StockDataService { webSearchService; constructor() { this.webSearchService = new WebSearchService(); } isAvailable() { return this.webSearchService.isAvailable(); } async getStockData(request) { if (!this.webSearchService.isAvailable()) { throw new Error('Web search service not available. Please check Claude API configuration.'); } const { symbol, company_name, include_history = true, history_period = '3m' } = request; try { // Create financial data focused web search query const searchQuery = company_name ? `${company_name} ${symbol} stock price current market data financial information trading volume market cap` : `${symbol} stock price current market data financial information trading volume market cap`; // Removed debug output to prevent JSON-RPC contamination // Use the existing MCP web search service with financial domains const webSearchRequest = { arguments: { query: searchQuery, max_uses: 3, allowed_domains: [ 'finance.yahoo.com', 'bloomberg.com', 'marketwatch.com', 'reuters.com', 'investing.com', 'nasdaq.com', 'cnbc.com' ] } }; const searchResult = await this.webSearchService.search(webSearchRequest.arguments); if (!searchResult || !searchResult.answer) { throw new Error('Web search failed: No results returned'); } // Parse the search results to extract stock data const stockData = this.extractStockDataFromSearchResults(searchResult, symbol, company_name); // Validate and format the response const validatedData = { success: true, symbol: symbol, company_name: stockData.company_name || company_name || symbol, current_data: { current_price: stockData.current_price || 0, change: stockData.change || 0, change_percent: stockData.change_percent || 0, volume: stockData.volume || 0, market_cap: stockData.market_cap || 'N/A', pe_ratio: stockData.pe_ratio, day_high: stockData.day_high || 0, day_low: stockData.day_low || 0, fifty_two_week_high: stockData.fifty_two_week_high || 0, fifty_two_week_low: stockData.fifty_two_week_low || 0 }, timestamp: new Date().toISOString(), source: 'claude_web_search_financial' }; if (include_history && stockData.history && Array.isArray(stockData.history)) { validatedData.history = stockData.history; } // Successfully extracted data - removed debug output return validatedData; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); // Error logged internally - removed console output return { success: false, symbol, company_name: company_name || symbol, current_data: { current_price: 0, change: 0, change_percent: 0, volume: 0, market_cap: 'N/A', day_high: 0, day_low: 0, fifty_two_week_high: 0, fifty_two_week_low: 0 }, timestamp: new Date().toISOString(), source: 'claude_web_search_financial', error: errorMessage }; } } extractStockDataFromSearchResults(searchResult, symbol, company_name) { // Extract stock data from web search results const searchText = searchResult.results?.map((r) => r.snippet || r.content || '').join(' ') || searchResult.answer || JSON.stringify(searchResult); // Parsing search results - removed debug output const data = { symbol, company_name: company_name || symbol, current_price: 0, change: 0, change_percent: 0, volume: 0, market_cap: 'N/A', day_high: 0, day_low: 0, fifty_two_week_high: 0, fifty_two_week_low: 0 }; // Extract current price (pattern: $123.45 or 123.45) const pricePattern = /(?:price|trading|quote)[\s:]*\$?(\d+\.?\d*)/i; const priceMatch = searchText.match(pricePattern) || searchText.match(/\$(\d+\.?\d*)/); if (priceMatch) { data.current_price = parseFloat(priceMatch[1]); } // Extract change (pattern: +1.23 or -1.23) const changePattern = /([\+\-]\$?\d+\.?\d*)/; const changeMatch = searchText.match(changePattern); if (changeMatch) { data.change = parseFloat(changeMatch[1].replace(/[^\d.-]/g, '')); } // Extract percentage change (pattern: +1.23% or -1.23%) const percentPattern = /([\+\-]?\d+\.?\d*)%/; const percentMatch = searchText.match(percentPattern); if (percentMatch) { data.change_percent = parseFloat(percentMatch[1]); } // Extract volume (pattern: Volume: 1,234,567) const volumePattern = /volume[\s:]*(\d+[\d,]*)/i; const volumeMatch = searchText.match(volumePattern); if (volumeMatch) { data.volume = parseInt(volumeMatch[1].replace(/,/g, '')); } // Extract market cap (pattern: Market Cap: $1.2T) const marketCapPattern = /market cap[\s:]*\$?(\d+\.?\d*[KMBT]?)/i; const marketCapMatch = searchText.match(marketCapPattern); if (marketCapMatch) { data.market_cap = '$' + marketCapMatch[1]; } // Extract day high/low (pattern: High: 125.00, Low: 122.00) const highPattern = /high[\s:]*\$?(\d+\.?\d*)/i; const lowPattern = /low[\s:]*\$?(\d+\.?\d*)/i; const highMatch = searchText.match(highPattern); const lowMatch = searchText.match(lowPattern); if (highMatch) data.day_high = parseFloat(highMatch[1]); if (lowMatch) data.day_low = parseFloat(lowMatch[1]); // Extract 52-week high/low const fiftyTwoWeekHighPattern = /52.week high[\s:]*\$?(\d+\.?\d*)/i; const fiftyTwoWeekLowPattern = /52.week low[\s:]*\$?(\d+\.?\d*)/i; const fiftyTwoHighMatch = searchText.match(fiftyTwoWeekHighPattern); const fiftyTwoLowMatch = searchText.match(fiftyTwoWeekLowPattern); if (fiftyTwoHighMatch) data.fifty_two_week_high = parseFloat(fiftyTwoHighMatch[1]); if (fiftyTwoLowMatch) data.fifty_two_week_low = parseFloat(fiftyTwoLowMatch[1]); // Extract P/E ratio const pePattern = /p\/e ratio[\s:]*(\d+\.?\d*)/i; const peMatch = searchText.match(pePattern); if (peMatch) { data.pe_ratio = parseFloat(peMatch[1]); } return data; } parseStockDataFromText(text, symbol, company_name) { // Fallback text parsing for when JSON parsing fails const data = { symbol, company_name: company_name || symbol, current_data: {} }; // Extract price patterns const priceMatch = text.match(/\$?(\d+\.?\d*)/); if (priceMatch) { data.current_data.current_price = parseFloat(priceMatch[1]); } // Extract change patterns const changeMatch = text.match(/[\+\-]?\$?(\d+\.?\d*)/); if (changeMatch) { data.current_data.change = parseFloat(changeMatch[1]); } // Extract percentage patterns const percentMatch = text.match(/[\+\-]?(\d+\.?\d*)%/); if (percentMatch) { data.current_data.change_percent = parseFloat(percentMatch[1]); } return data; } parseFloat(value) { if (typeof value === 'number') return value; if (typeof value === 'string') { const parsed = parseFloat(value.replace(/[^\d.-]/g, '')); return isNaN(parsed) ? undefined : parsed; } return undefined; } parseInt(value) { if (typeof value === 'number') return Math.floor(value); if (typeof value === 'string') { const parsed = parseInt(value.replace(/[^\d]/g, ''), 10); return isNaN(parsed) ? undefined : parsed; } return undefined; } getConfiguration() { return { service: 'stock_data', version: '1.0.0', provider: 'claude_web_search', available: this.isAvailable(), supported_symbols: 'All major stock exchanges', data_sources: [ 'finance.yahoo.com', 'bloomberg.com', 'marketwatch.com', 'reuters.com', 'investing.com', 'nasdaq.com', 'cnbc.com' ] }; } }