Skip to main content
Glama

ibex35-mcp

index.ts24.7 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, Tool, } from '@modelcontextprotocol/sdk/types.js'; import { DatabaseManager } from './database.js'; import { AnalyticsManager } from './analytics.js'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); class IBEX35MCPServer { private server: Server; private db: DatabaseManager; private analytics: AnalyticsManager; constructor() { this.server = new Server( { name: 'ibex35-database-server', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Initialize database connection to Cloudflare Worker API const apiUrl = process.env.IBEX35_API_URL || 'https://ibex35-api.ncdata.eu'; const apiKey = process.env.IBEX35_API_KEY; this.db = new DatabaseManager({ apiUrl, apiKey }); this.analytics = new AnalyticsManager(this.db); this.setupToolHandlers(); this.setupErrorHandling(); } private setupToolHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ // Company queries { name: 'get_all_companies', description: 'Get all IBEX 35 companies with current prices and key metrics', inputSchema: { type: 'object', properties: {}, }, }, { name: 'get_company_by_symbol', description: 'Get detailed information for a specific company by its stock symbol', inputSchema: { type: 'object', properties: { symbol: { type: 'string', description: 'Stock symbol (e.g., SAN, TEF, IBE)', }, }, required: ['symbol'], }, }, { name: 'get_companies_by_sector', description: 'Get companies filtered by sector', inputSchema: { type: 'object', properties: { sector: { type: 'string', description: 'Sector name or partial match (e.g., Banking, Technology, Energy)', }, }, required: ['sector'], }, }, { name: 'get_companies_with_pe_ratio', description: 'Get companies filtered by P/E ratio range', inputSchema: { type: 'object', properties: { minPE: { type: 'number', description: 'Minimum P/E ratio', }, maxPE: { type: 'number', description: 'Maximum P/E ratio', }, }, }, }, // Director and governance queries { name: 'get_company_directors', description: 'Get board directors for a specific company', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Company ID or use get_company_by_symbol first to get ID', }, }, required: ['companyId'], }, }, { name: 'get_board_interlocks', description: 'Find directors who serve on multiple IBEX 35 company boards', inputSchema: { type: 'object', properties: {}, }, }, { name: 'get_directors_by_name', description: 'Search for directors by name across all companies', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Director name or partial match', }, }, required: ['name'], }, }, // Shareholder queries { name: 'get_company_shareholders', description: 'Get shareholders for a specific company', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Company ID', }, }, required: ['companyId'], }, }, { name: 'get_shareholder_overlap', description: 'Find shareholders who own stakes in multiple IBEX 35 companies', inputSchema: { type: 'object', properties: {}, }, }, { name: 'get_top_shareholders_by_sector', description: 'Get top shareholders in a specific sector', inputSchema: { type: 'object', properties: { sector: { type: 'string', description: 'Sector name', }, limit: { type: 'number', description: 'Maximum number of results', default: 10, }, }, required: ['sector'], }, }, // Market data queries { name: 'get_historical_prices', description: 'Get historical price data for a company', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Company ID', }, days: { type: 'number', description: 'Number of days of historical data', default: 30, }, }, required: ['companyId'], }, }, { name: 'get_top_performers', description: 'Get top performing stocks over a specified period', inputSchema: { type: 'object', properties: { days: { type: 'number', description: 'Period in days', default: 7, }, limit: { type: 'number', description: 'Maximum number of results', default: 10, }, }, }, }, // News and sentiment { name: 'get_recent_news', description: 'Get recent news articles, optionally filtered by company', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Optional: Company ID to filter by', }, limit: { type: 'number', description: 'Maximum number of articles', default: 20, }, }, }, }, { name: 'get_news_by_sentiment', description: 'Get news articles filtered by sentiment', inputSchema: { type: 'object', properties: { sentiment: { type: 'string', enum: ['positive', 'negative', 'neutral'], description: 'News sentiment', }, limit: { type: 'number', description: 'Maximum number of articles', default: 20, }, }, required: ['sentiment'], }, }, // Lobbying and transparency { name: 'get_lobbying_meetings', description: 'Get EU lobbying meetings, optionally filtered by company', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Optional: Company ID to filter by', }, limit: { type: 'number', description: 'Maximum number of meetings', default: 20, }, }, }, }, { name: 'get_most_active_lobbyists', description: 'Get organizations with the most EU lobbying meetings', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of results', default: 10, }, }, }, }, // ESG data { name: 'get_esg_scores', description: 'Get ESG (Environmental, Social, Governance) scores', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Optional: Company ID to filter by', }, }, }, }, // Weekly reports { name: 'get_weekly_reports', description: 'Get generated weekly reports and analysis', inputSchema: { type: 'object', properties: { reportType: { type: 'string', enum: ['market_overview', 'sector_analysis', 'governance_highlights', 'full_report'], description: 'Type of report to filter by', }, limit: { type: 'number', description: 'Maximum number of reports', default: 10, }, }, }, }, // Advanced Analytics { name: 'get_network_analysis', description: 'Get comprehensive network analysis of board interlocks and shareholder relationships', inputSchema: { type: 'object', properties: {}, }, }, { name: 'get_sector_correlation_analysis', description: 'Analyze sector performance correlations and market trends', inputSchema: { type: 'object', properties: { days: { type: 'number', description: 'Number of days to analyze', default: 30, }, }, }, }, // Enhanced query processing and analysis { name: 'analyze_natural_query', description: 'Process and execute complex natural language queries about companies, financials, governance, or markets', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Natural language query (e.g., "Which banking stocks have grown most in the last month?", "Show me companies with high governance risk", "Compare energy sector performance")', }, context: { type: 'string', description: 'Optional context or previous query results to build upon', }, }, required: ['query'], }, }, { name: 'compare_companies', description: 'Compare multiple companies across various metrics (financial, governance, market performance)', inputSchema: { type: 'object', properties: { companies: { type: 'array', items: { type: 'string', }, description: 'List of company symbols or names to compare', }, metrics: { type: 'array', items: { type: 'string', enum: ['financial', 'governance', 'market_performance', 'sector_position', 'risk_profile', 'all'], }, description: 'Metrics to compare (defaults to all if not specified)', default: ['all'], }, }, required: ['companies'], }, }, { name: 'analyze_trends', description: 'Analyze trends in stock prices, market performance, or sector movements over time', inputSchema: { type: 'object', properties: { analysis_type: { type: 'string', enum: ['company_trend', 'sector_trend', 'market_trend', 'correlation_analysis'], description: 'Type of trend analysis to perform', }, target: { type: 'string', description: 'Company symbol, sector name, or "market" for overall analysis', }, period: { type: 'number', description: 'Number of days to analyze', default: 30, }, include_forecast: { type: 'boolean', description: 'Whether to include simple trend forecast', default: false, }, }, required: ['analysis_type', 'target'], }, }, { name: 'assess_investment_risk', description: 'Comprehensive risk assessment for companies or sectors including market, governance, and operational risks', inputSchema: { type: 'object', properties: { target: { type: 'string', description: 'Company symbol, sector name, or portfolio of companies', }, risk_types: { type: 'array', items: { type: 'string', enum: ['market_risk', 'governance_risk', 'sector_risk', 'liquidity_risk', 'concentration_risk', 'all'], }, description: 'Types of risk to assess', default: ['all'], }, }, required: ['target'], }, }, { name: 'generate_analyst_report', description: 'Generate a comprehensive analyst report for a company, sector, or market theme', inputSchema: { type: 'object', properties: { subject: { type: 'string', description: 'Company symbol, sector name, or theme to analyze', }, report_type: { type: 'string', enum: ['company_deep_dive', 'sector_overview', 'governance_analysis', 'market_opportunity', 'risk_assessment'], description: 'Type of report to generate', }, include_charts: { type: 'boolean', description: 'Whether to include data visualizations (text-based)', default: true, }, }, required: ['subject', 'report_type'], }, }, { name: 'screen_opportunities', description: 'Screen for investment opportunities based on specific criteria (value, growth, dividend, ESG, etc.)', inputSchema: { type: 'object', properties: { screening_criteria: { type: 'object', properties: { pe_ratio_max: { type: 'number', description: 'Maximum P/E ratio', }, pe_ratio_min: { type: 'number', description: 'Minimum P/E ratio', }, market_cap_min: { type: 'number', description: 'Minimum market capitalization', }, market_cap_max: { type: 'number', description: 'Maximum market capitalization', }, sectors: { type: 'array', items: { type: 'string', }, description: 'Specific sectors to include', }, exclude_sectors: { type: 'array', items: { type: 'string', }, description: 'Sectors to exclude', }, performance_period: { type: 'number', description: 'Days to look back for performance metrics', default: 30, }, governance_quality: { type: 'string', enum: ['high', 'medium', 'low', 'any'], description: 'Required governance quality level', default: 'any', }, }, }, limit: { type: 'number', description: 'Maximum number of opportunities to return', default: 10, }, }, required: ['screening_criteria'], }, }, // Custom queries { name: 'execute_custom_query', description: 'Execute a custom SQL query on the database (SELECT only)', inputSchema: { type: 'object', properties: { sql: { type: 'string', description: 'SQL SELECT query to execute', }, params: { type: 'array', items: { type: 'string', }, description: 'Optional parameters for the query', default: [], }, }, required: ['sql'], }, }, ] as Tool[], }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { let result: any; switch (name) { case 'get_all_companies': result = await this.db.getAllCompanies(); break; case 'get_company_by_symbol': result = await this.db.getCompanyBySymbol((args as any)?.symbol); break; case 'get_companies_by_sector': result = await this.db.getCompaniesBySector((args as any)?.sector); break; case 'get_companies_with_pe_ratio': result = await this.db.getCompaniesWithPERatio((args as any)?.minPE, (args as any)?.maxPE); break; case 'get_company_directors': result = await this.db.getCompanyDirectors((args as any)?.companyId); break; case 'get_board_interlocks': result = await this.db.getBoardInterlocks(); break; case 'get_directors_by_name': result = await this.db.getDirectorsByName((args as any)?.name); break; case 'get_company_shareholders': result = await this.db.getCompanyShareholders((args as any)?.companyId); break; case 'get_shareholder_overlap': result = await this.db.getShareholderOverlap(); break; case 'get_top_shareholders_by_sector': result = await this.db.getTopShareholdersBySector((args as any)?.sector, (args as any)?.limit || 10); break; case 'get_historical_prices': result = await this.db.getHistoricalPrices((args as any)?.companyId, (args as any)?.days || 30); break; case 'get_top_performers': result = await this.db.getTopPerformers((args as any)?.days || 7, (args as any)?.limit || 10); break; case 'get_recent_news': result = await this.db.getRecentNews((args as any)?.companyId, (args as any)?.limit || 20); break; case 'get_news_by_sentiment': result = await this.db.getNewsBySentiment((args as any)?.sentiment, (args as any)?.limit || 20); break; case 'get_lobbying_meetings': result = await this.db.getLobbyingMeetings((args as any)?.companyId, (args as any)?.limit || 20); break; case 'get_most_active_lobbyists': result = await this.db.getMostActiveLobbyists((args as any)?.limit || 10); break; case 'get_esg_scores': result = await this.db.getESGScores((args as any)?.companyId); break; case 'get_weekly_reports': result = await this.db.getWeeklyReports((args as any)?.reportType, (args as any)?.limit || 10); break; case 'get_network_analysis': result = await this.analytics.getComplexNetworkAnalysis(); break; case 'get_sector_correlation_analysis': result = await this.analytics.getSectorCorrelationAnalysis((args as any)?.days || 30); break; case 'analyze_natural_query': result = await this.analytics.analyzeNaturalQuery((args as any)?.query, (args as any)?.context); break; case 'compare_companies': result = await this.analytics.compareCompanies((args as any)?.companies, (args as any)?.metrics || ['all']); break; case 'analyze_trends': result = await this.analytics.analyzeTrends( (args as any)?.analysis_type, (args as any)?.target, (args as any)?.period || 30, (args as any)?.include_forecast || false ); break; case 'assess_investment_risk': result = await this.analytics.assessInvestmentRisk((args as any)?.target, (args as any)?.risk_types || ['all']); break; case 'generate_analyst_report': result = await this.analytics.generateAnalystReport( (args as any)?.subject, (args as any)?.report_type, (args as any)?.include_charts !== false ); break; case 'screen_opportunities': result = await this.analytics.screenOpportunities((args as any)?.screening_criteria, (args as any)?.limit || 10); break; case 'execute_custom_query': result = await this.db.executeCustomQuery((args as any)?.sql, (args as any)?.params || []); break; default: throw new Error(`Unknown tool: ${name}`); } return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); } private setupErrorHandling() { this.server.onerror = (error) => { console.error('[MCP Error]', error); }; process.on('SIGINT', async () => { await this.server.close(); this.db.close(); process.exit(0); }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('IBEX 35 MCP server running on stdio'); } } const server = new IBEX35MCPServer(); server.run().catch(console.error);

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/anbrme/ibex35-mcp-server'

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