UNPKG

stock-market-mcp-server

Version:

Financial Datasets MCP Server for Stock Market API

1,062 lines (1,061 loc) • 151 kB
/** * Financial Datasets MCP Server * A low-level server implementation using Model Context Protocol for Stock Market API */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, CompleteRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import axios from 'axios'; const logFile = path.join(os.tmpdir(), 'financial-mcp.log'); fs.writeFileSync(logFile, `[INFO] ${new Date().toISOString()} - Starting Financial Datasets MCP Server...\n`); console.log = (...args) => { const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' '); fs.appendFileSync(logFile, `[INFO] ${new Date().toISOString()} - ${message}\n`); }; console.error = (...args) => { const message = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : arg).join(' '); fs.appendFileSync(logFile, `[ERROR] ${new Date().toISOString()} - ${message}\n`); }; const logger = { log: (message) => { fs.appendFileSync(logFile, `[INFO] ${new Date().toISOString()} - ${message}\n`); }, error: (message, error) => { fs.appendFileSync(logFile, `[ERROR] ${new Date().toISOString()} - ${message}\n`); if (error) { fs.appendFileSync(logFile, `${error.stack || error}\n`); } } }; let financialConfig; let apiClient; /** * Helper function to safely extract parameters from request arguments */ function safeGetArgs(args, defaultValues) { if (!args || typeof args !== 'object') { return defaultValues; } const result = { ...defaultValues }; for (const key in defaultValues) { if (args[key] !== undefined) { result[key] = args[key]; } } return result; } /** * Helper function to recursively find text content in a response object */ function findTextInObject(obj) { if (typeof obj === 'string') { return obj; } if (typeof obj === 'object' && obj !== null) { // Check common text properties if (obj.text && typeof obj.text === 'string') { return obj.text; } if (obj.content && typeof obj.content === 'string') { return obj.content; } if (obj.message && typeof obj.message === 'string') { return obj.message; } // Recursively search in nested objects for (const key in obj) { if (obj.hasOwnProperty(key)) { const result = findTextInObject(obj[key]); if (result) { return result; } } } } return null; } /** * Helper function to request LLM sampling from the client */ async function requestSampling(server, messages, systemPrompt, modelPreferences) { console.log('šŸš€ [TRANSPORT] === STARTING SAMPLING REQUEST ==='); try { logger.log('Initiating sampling request to client'); const samplingParams = { messages, systemPrompt: systemPrompt || "You are a financial analysis expert. Provide clear, accurate, and actionable insights.", modelPreferences: modelPreferences || { hints: [ { name: "claude-3-sonnet" }, { name: "gpt-4" }, { name: "claude" } ], intelligencePriority: 0.9, speedPriority: 0.6, costPriority: 0.4 }, maxTokens: 4000 }; logger.log('Sending sampling request with params: ' + JSON.stringify(samplingParams, null, 2)); // TRANSPORT LOG: Sampling request being sent to client console.log('\nšŸ“” [TRANSPORT] SENDING SAMPLING REQUEST TO CLIENT:'); console.log('====================================='); console.log('Method: sampling/createMessage'); console.log('Message Count:', samplingParams.messages.length); console.log('System Prompt Length:', samplingParams.systemPrompt?.length || 0, 'characters'); console.log('Model Preferences:', JSON.stringify(samplingParams.modelPreferences, null, 2)); console.log('Max Tokens:', samplingParams.maxTokens); console.log('Message Preview (first 200 chars):', samplingParams.messages[0]?.content?.text?.substring(0, 200) + '...'); console.log('=====================================\n'); // Send the sampling request to the client let response; try { console.log('šŸ”„ [TRANSPORT] CALLING server.request() for sampling...'); console.log('šŸ” [TRANSPORT] Server object type:', typeof server); console.log('šŸ” [TRANSPORT] Server has request method:', typeof server.request); console.log('šŸ” [TRANSPORT] Server methods:', Object.getOwnPropertyNames(server)); console.log('šŸ” [TRANSPORT] Server prototype methods:', Object.getOwnPropertyNames(Object.getPrototypeOf(server))); console.log('šŸ” [TRANSPORT] Server constructor name:', server.constructor.name); // Check available methods for sampling console.log('šŸ” [TRANSPORT] Checking for sampling methods...'); console.log('šŸ” [TRANSPORT] server.request:', typeof server.request); console.log('šŸ” [TRANSPORT] server.requestSampling:', typeof server.requestSampling); console.log('šŸ” [TRANSPORT] server.createMessage:', typeof server.createMessage); console.log('šŸ” [TRANSPORT] server.sendRequest:', typeof server.sendRequest); // Try different methods based on what's available let requestMethod = null; let methodName = ''; if (typeof server.requestSampling === 'function') { requestMethod = server.requestSampling.bind(server); methodName = 'requestSampling'; } else if (typeof server.createMessage === 'function') { requestMethod = server.createMessage.bind(server); methodName = 'createMessage'; } else if (typeof server.sendRequest === 'function') { requestMethod = server.sendRequest.bind(server); methodName = 'sendRequest'; } else if (typeof server.request === 'function') { requestMethod = server.request.bind(server); methodName = 'request'; } else { console.error('āŒ [TRANSPORT] Server does not have any request methods'); throw new Error('Server instance does not support making requests to client'); } console.log(`āœ… [TRANSPORT] Using method: ${methodName}`); // Create the request object const requestObject = { method: "sampling/createMessage", params: samplingParams }; console.log('šŸ“¤ [TRANSPORT] Request object:', JSON.stringify(requestObject, null, 2)); // Use the appropriate method based on what's available if (methodName === 'requestSampling') { console.log('šŸ”„ [TRANSPORT] Using requestSampling method...'); response = await requestMethod(samplingParams); } else if (methodName === 'createMessage') { console.log('šŸ”„ [TRANSPORT] Using createMessage method...'); response = await requestMethod(samplingParams); } else { console.log(`šŸ”„ [TRANSPORT] Using ${methodName} method...`); response = await requestMethod(requestObject); } console.log('āœ… [TRANSPORT] SAMPLING REQUEST COMPLETED SUCCESSFULLY'); } catch (requestError) { console.error('āŒ [TRANSPORT] SAMPLING REQUEST FAILED:', requestError); console.error('Error details:', { name: requestError instanceof Error ? requestError.name : 'Unknown', message: requestError instanceof Error ? requestError.message : String(requestError), stack: requestError instanceof Error ? requestError.stack : 'No stack trace' }); // Check if it's the specific parsing error if (requestError instanceof Error && requestError.message.includes('Cannot read properties of undefined')) { console.error('🚨 [TRANSPORT] DETECTED PARSING ERROR - This might be an MCP SDK issue'); console.error('Full error object:', JSON.stringify(requestError, null, 2)); // For now, return a placeholder indicating sampling is not working console.log('āš ļø [TRANSPORT] SAMPLING NOT WORKING - RETURNING PLACEHOLDER'); return "āš ļø **AI Analysis Not Available** āš ļø\n\nSampling request failed due to MCP SDK limitations. The server can send sampling requests to the client, but cannot receive the responses properly.\n\n**Technical Details:**\n- Client successfully receives sampling requests\n- Client generates LLM responses\n- Server fails to parse the response due to MCP SDK issue\n\n**Workaround needed:** This requires fixing the MCP transport layer or using a different approach for server-to-client sampling requests."; } throw new Error(`Sampling request failed: ${requestError instanceof Error ? requestError.message : 'Unknown error'}`); } // TRANSPORT LOG: Raw sampling response received from client console.log('\nšŸ”„ [TRANSPORT] SAMPLING RESPONSE RECEIVED FROM CLIENT:'); console.log('====================================='); console.log(JSON.stringify(response, null, 2)); console.log('=====================================\n'); logger.log('Received sampling response: ' + JSON.stringify(response)); // Extract the text content from the response let extractedText; // Handle different possible response formats try { if (response && typeof response === 'object') { // Check for standard MCP sampling response format if (response.content && response.content.type === 'text' && response.content.text) { extractedText = response.content.text; console.log('šŸ“ [TRANSPORT] EXTRACTED TEXT FROM SAMPLING RESPONSE (content.text):'); } // Check for direct text property else if (response.text && typeof response.text === 'string') { extractedText = response.text; console.log('šŸ“ [TRANSPORT] EXTRACTED TEXT FROM SAMPLING RESPONSE (.text):'); } // Check for result property (some MCP implementations) else if (response.result && response.result.content && response.result.content.text) { extractedText = response.result.content.text; console.log('šŸ“ [TRANSPORT] EXTRACTED TEXT FROM SAMPLING RESPONSE (result.content.text):'); } // Check if response itself has the text directly else if (typeof response.content === 'string') { extractedText = response.content; console.log('šŸ“ [TRANSPORT] EXTRACTED TEXT FROM SAMPLING RESPONSE (content as string):'); } else { // Try to find any text property recursively const textValue = findTextInObject(response); if (textValue) { extractedText = textValue; console.log('šŸ“ [TRANSPORT] EXTRACTED TEXT FROM SAMPLING RESPONSE (found recursively):'); } else { console.error('āŒ [TRANSPORT] NO TEXT FOUND IN SAMPLING RESPONSE:', JSON.stringify(response, null, 2)); throw new Error('No text content found in sampling response'); } } } // Handle string response else if (typeof response === 'string') { extractedText = response; console.log('šŸ“ [TRANSPORT] RESPONSE IS STRING:'); } else { console.error('āŒ [TRANSPORT] UNEXPECTED SAMPLING RESPONSE FORMAT:', response); throw new Error('Received unexpected response format from sampling request'); } // Log the extracted text details console.log('Text Length:', extractedText.length, 'characters'); console.log('First 200 chars:', extractedText.substring(0, 200) + (extractedText.length > 200 ? '...' : '')); console.log('Last 100 chars:', extractedText.length > 100 ? '...' + extractedText.substring(extractedText.length - 100) : extractedText); console.log(''); return extractedText; } catch (parseError) { console.error('āŒ [TRANSPORT] ERROR PARSING SAMPLING RESPONSE:', parseError); console.error('Raw response:', JSON.stringify(response, null, 2)); throw new Error(`Failed to parse sampling response: ${parseError instanceof Error ? parseError.message : 'Unknown parsing error'}`); } } catch (error) { logger.error('šŸ’„ [TRANSPORT] === SAMPLING REQUEST FAILED ==='); logger.error('Error type:', typeof error); logger.error('Error constructor:', error?.constructor?.name); logger.error('Error message:', error instanceof Error ? error.message : String(error)); logger.error('Error stack:', error instanceof Error ? error.stack : 'No stack'); logger.error('Full error object:', JSON.stringify(error, null, 2)); logger.error('Sampling request failed T:', error); throw new Error(`Failed to request LLM analysis: ${error instanceof Error ? error.message : 'Unknown error'}`); } finally { console.log('šŸ [TRANSPORT] === SAMPLING REQUEST COMPLETE ===\n'); } } function parseArgs() { // First check for environment variables (used when running in npx mode) if (process.env.FINANCIAL_API_KEY) { logger.log('Using API key from environment variable'); return { apiKey: process.env.FINANCIAL_API_KEY, baseUrl: process.env.FINANCIAL_API_BASE_URL || 'https://api.financialdatasets.ai' }; } // Otherwise parse from command line const args = process.argv.slice(2); const config = { baseUrl: 'https://api.financialdatasets.ai', apiKey: '' }; for (let i = 0; i < args.length; i++) { const arg = args[i]; if (arg === '--api-key' && i + 1 < args.length) { config.apiKey = args[++i]; } else if (arg === '--base-url' && i + 1 < args.length) { config.baseUrl = args[++i]; } } if (!config.apiKey) { throw new Error('Financial Datasets API key is required. Use --api-key argument or set FINANCIAL_API_KEY environment variable.'); } return config; } function initApiClient(config) { return axios.create({ baseURL: config.baseUrl, headers: { 'X-API-KEY': config.apiKey, 'Content-Type': 'application/json' }, timeout: 10000 }); } const server = new Server({ name: "financial-mcp-server", version: "1.0.0" }, { capabilities: { resources: { read: true, list: true, templates: true }, tools: { list: true, call: true }, prompts: { list: true, get: true, listChanged: true }, completion: { complete: true }, sampling: { createMessage: true } } }); async function fetchAvailableTickers(limit = 20) { try { logger.log('Fetching available tickers...'); // This is a hypothetical endpoint - adjust as needed const response = await apiClient.get('/company/facts/tickers/'); const tickers = response.data.tickers || []; logger.log(`Found ${tickers.length} tickers`); return tickers.slice(0, limit); } catch (error) { logger.error('Error fetching tickers:', error); // Return some common tickers if API fails return ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'META']; } } async function fetchAvailableCryptoTickers(limit = 10) { try { logger.log('Fetching available crypto tickers...'); const response = await apiClient.get('/crypto/prices/tickers/'); const tickers = response.data.tickers || []; logger.log(`Found ${tickers.length} crypto tickers`); return tickers.slice(0, limit); } catch (error) { logger.error('Error fetching crypto tickers:', error); // Return some common crypto tickers if API fails return ['BTC-USD', 'ETH-USD', 'SOL-USD', 'DOGE-USD', 'XRP-USD']; } } // === FRESH RESOURCES IMPLEMENTATION === // Following MCP 2025-06-18 specification exactly /** * List available tools for interacting with financial data. */ server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { "name": "get_company_facts", "description": "Get company facts including name, CIK, market cap, employees, etc.", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company (e.g., AAPL)." }, "cik": { "type": "string", "description": "The CIK (Central Index Key) of the company." } }, "required": [] } }, { "name": "get_stock_prices", "description": "Get historical stock prices for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company (e.g., AAPL)." }, "period": { "type": "string", "description": "Time period for the data (e.g., '1d', '1m', '1y')." }, "limit": { "type": "integer", "description": "Maximum number of records to return.", "default": 30 } }, "required": ["ticker"] } }, { "name": "search_companies", "description": "Search for companies by name or industry", "inputSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "Search query for company name, industry, or sector." }, "limit": { "type": "integer", "description": "Maximum number of results to return.", "default": 10 } }, "required": ["query"] } }, { "name": "get_crypto_prices", "description": "Get historical price data for a cryptocurrency", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The cryptocurrency ticker symbol (e.g., BTC-USD)." }, "interval": { "type": "string", "description": "The time interval for price data ('minute', 'day', 'week', 'month', 'year').", "enum": ["minute", "day", "week", "month", "year"] }, "interval_multiplier": { "type": "integer", "description": "The multiplier for the interval (e.g., 5 for every 5 minutes).", "minimum": 1 }, "start_date": { "type": "string", "description": "The start date for price data (format: YYYY-MM-DD)." }, "end_date": { "type": "string", "description": "The end date for price data (format: YYYY-MM-DD)." }, "limit": { "type": "integer", "description": "Maximum number of price records to return.", "default": 1000, "maximum": 5000, "minimum": 1 } }, "required": ["ticker", "interval", "interval_multiplier", "start_date", "end_date"] } }, { "name": "get_crypto_snapshot", "description": "Get the current price snapshot for a cryptocurrency", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The cryptocurrency ticker symbol (e.g., BTC-USD)." } }, "required": ["ticker"] } }, { "name": "get_earnings_press_releases", "description": "Get earnings press releases for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." } }, "required": ["ticker"] } }, { "name": "get_financial_metrics", "description": "Get historical financial metrics for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "period": { "type": "string", "description": "The time period for the data ('annual', 'quarterly', 'ttm').", "enum": ["annual", "quarterly", "ttm"] }, "limit": { "type": "integer", "description": "Maximum number of records to return.", "default": 4 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker", "period"] } }, { "name": "get_financial_metrics_snapshot", "description": "Get current financial metrics snapshot for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." } }, "required": ["ticker"] } }, { "name": "get_income_statements", "description": "Get income statements for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "cik": { "type": "string", "description": "Alternative: The CIK of the company." }, "period": { "type": "string", "description": "The time period for the data ('annual', 'quarterly', 'ttm').", "enum": ["annual", "quarterly", "ttm"] }, "limit": { "type": "integer", "description": "Maximum number of records to return.", "default": 4 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker", "period"] } }, { "name": "get_balance_sheets", "description": "Get balance sheets for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "cik": { "type": "string", "description": "Alternative: The CIK of the company." }, "period": { "type": "string", "description": "The time period for the data ('annual', 'quarterly', 'ttm').", "enum": ["annual", "quarterly", "ttm"] }, "limit": { "type": "integer", "description": "Maximum number of records to return.", "default": 4 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker", "period"] } }, { "name": "get_cash_flow_statements", "description": "Get cash flow statements for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "cik": { "type": "string", "description": "Alternative: The CIK of the company." }, "period": { "type": "string", "description": "The time period for the data ('annual', 'quarterly', 'ttm').", "enum": ["annual", "quarterly", "ttm"] }, "limit": { "type": "integer", "description": "Maximum number of records to return.", "default": 4 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker", "period"] } }, { "name": "get_all_financial_statements", "description": "Get all financial statements for a company in one call", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "cik": { "type": "string", "description": "Alternative: The CIK of the company." }, "period": { "type": "string", "description": "The time period for the data ('annual', 'quarterly', 'ttm').", "enum": ["annual", "quarterly", "ttm"] }, "limit": { "type": "integer", "description": "Maximum number of records to return.", "default": 4 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker", "period"] } }, { "name": "get_insider_trades", "description": "Get insider trades (buys and sells) for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "limit": { "type": "integer", "description": "Maximum number of trades to return.", "default": 100, "maximum": 1000 }, "filing_date_gte": { "type": "string", "description": "Filter for filing dates greater than or equal to date (format: YYYY-MM-DD)." }, "filing_date_lte": { "type": "string", "description": "Filter for filing dates less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker"] } }, { "name": "get_institutional_ownership_by_investor", "description": "Get institutional ownership data by investor", "inputSchema": { "type": "object", "properties": { "investor": { "type": "string", "description": "The name of the investment manager (e.g., BERKSHIRE_HATHAWAY_INC)." }, "limit": { "type": "integer", "description": "Maximum number of holdings to return.", "default": 10 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["investor"] } }, { "name": "get_institutional_ownership_by_ticker", "description": "Get institutional ownership data by ticker", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "limit": { "type": "integer", "description": "Maximum number of institutional owners to return.", "default": 10 }, "report_period_gte": { "type": "string", "description": "Filter for report periods greater than or equal to date (format: YYYY-MM-DD)." }, "report_period_lte": { "type": "string", "description": "Filter for report periods less than or equal to date (format: YYYY-MM-DD)." } }, "required": ["ticker"] } }, { "name": "get_company_news", "description": "Get news articles for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "start_date": { "type": "string", "description": "The start date for news articles (format: YYYY-MM-DD)." }, "end_date": { "type": "string", "description": "The end date for news articles (format: YYYY-MM-DD)." }, "limit": { "type": "integer", "description": "Maximum number of news articles to return.", "default": 100, "maximum": 100, "minimum": 1 } }, "required": ["ticker"] } }, { "name": "search_financials", "description": "Search for financial data across income statements, balance sheets, and cash flow statements", "inputSchema": { "type": "object", "properties": { "search_type": { "type": "string", "description": "Type of search to perform: 'filters' for filtering by metrics or 'line_items' for retrieving specific data points.", "enum": ["filters", "line_items"] }, "filters": { "type": "array", "description": "Array of filter objects to apply (required when search_type=filters).", "items": { "type": "object", "properties": { "field": { "type": "string", "description": "The financial metric to filter on (e.g., revenue, total_debt, capital_expenditure)." }, "operator": { "type": "string", "description": "The comparison operator.", "enum": ["eq", "gt", "gte", "lt", "lte"] }, "value": { "type": "number", "description": "The value to compare against." } }, "required": ["field", "operator", "value"] } }, "line_items": { "type": "array", "description": "Array of financial metrics to retrieve (required when search_type=line_items).", "items": { "type": "string" } }, "tickers": { "type": "array", "description": "Array of ticker symbols (required when search_type=line_items).", "items": { "type": "string" } }, "period": { "type": "string", "description": "The time period for the financial data.", "enum": ["annual", "quarterly", "ttm"], "default": "ttm" }, "limit": { "type": "integer", "description": "Maximum number of results to return.", "default": 100 }, "currency": { "type": "string", "description": "The currency for the financial data.", "enum": ["USD", "EUR", "GBP", "JPY", "CHF", "AUD", "CAD", "SEK"] }, "order_by": { "type": "string", "description": "Field to order results by.", "enum": ["ticker", "-ticker", "report_period", "-report_period"], "default": "ticker" } }, "required": ["search_type"] } }, { "name": "get_stock_price_snapshot", "description": "Get the real-time price snapshot for a stock ticker", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." } }, "required": ["ticker"] } }, { "name": "get_stock_prices_advanced", "description": "Get ranged price data for a ticker with customizable intervals", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "interval": { "type": "string", "description": "The time interval for price data.", "enum": ["second", "minute", "day", "week", "month", "year"] }, "interval_multiplier": { "type": "integer", "description": "The multiplier for the interval (e.g., 5 for every 5 minutes).", "minimum": 1 }, "start_date": { "type": "string", "description": "The start date for price data (format: YYYY-MM-DD)." }, "end_date": { "type": "string", "description": "The end date for price data (format: YYYY-MM-DD)." }, "limit": { "type": "integer", "description": "Maximum number of price records to return.", "default": 5000, "maximum": 5000, "minimum": 1 } }, "required": ["ticker", "interval", "interval_multiplier", "start_date", "end_date"] } }, { "name": "get_sec_filing_items", "description": "Get specific sections (items) from a company's SEC filings", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "filing_type": { "type": "string", "description": "The type of filing to extract items from.", "enum": ["10-K", "10-Q"] }, "year": { "type": "integer", "description": "The year of the filing." }, "quarter": { "type": "integer", "description": "The quarter of the filing if 10-Q.", "minimum": 1, "maximum": 4 }, "items": { "type": "array", "description": "Specific items to extract from the filing. If not provided, all items are returned.", "items": { "type": "string", "enum": ["Item-1", "Item-1A", "Item-1B", "Item-2", "Item-3", "Item-4", "Item-5", "Item-6", "Item-7", "Item-7A", "Item-8", "Item-9", "Item-9A", "Item-9B", "Item-10", "Item-11", "Item-12", "Item-13", "Item-14", "Item-15", "Item-16"] } } }, "required": ["ticker", "filing_type", "year"] } }, { "name": "get_segmented_revenues", "description": "Get detailed, segmented revenue data for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "cik": { "type": "string", "description": "Alternative: The CIK of the company." }, "period": { "type": "string", "description": "The time period for the data.", "enum": ["annual", "quarterly"] }, "limit": { "type": "integer", "description": "Maximum number of reports to return.", "default": 4 } }, "required": ["period"] } }, { "name": "get_sec_filings", "description": "Get a list of SEC filings for a company", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company." }, "cik": { "type": "string", "description": "Alternative: The CIK of the company." }, "filing_type": { "type": "string", "description": "Type of filing to filter results.", "enum": ["10-K", "10-Q", "8-K", "4", "144"] } }, "required": [] } }, { "name": "ai_financial_analysis", "description": "Get AI-powered financial analysis and insights using LLM sampling", "inputSchema": { "type": "object", "properties": { "ticker": { "type": "string", "description": "The ticker symbol of the company to analyze" }, "analysis_type": { "type": "string", "description": "Type of analysis to perform", "enum": ["comprehensive", "valuation", "risks", "opportunities", "comparison"] }, "context": { "type": "string", "description": "Additional context or specific questions for the analysis" } }, "required": ["ticker", "analysis_type"] } }, { "name": "ai_market_insights", "description": "Get AI-powered market insights and trend analysis using LLM sampling", "inputSchema": { "type": "object", "properties": { "focus_area": { "type": "string", "description": "Market focus area", "enum": ["overall_market", "sector_analysis", "economic_indicators", "risk_assessment"] }, "tickers": { "type": "array", "description": "Optional list of ticker symbols to focus on", "items": { "type": "string" } }, "context": { "type": "string", "description": "Specific questions or context for the market analysis" } },