Skip to main content
Glama

Chicken Business Management MCP Server

by PSYGER02
aiAssistant-enhanced.ts12.9 kB
/** * Enhanced AI Assistant Service with MCP Integration * Smart AI that proposes actions with human approval workflow * Now uses MCP server for reliable Gemini API calls with fallback */ import { supabase } from '../src/supabaseConfig'; import { geminiAPIManager } from './geminiAPIManager'; import { offlineDB } from './offlineService'; import { mcpIntegration } from './mcpIntegration'; interface AIProposal { id: string; type: 'expense_categorization' | 'stock_adjustment' | 'price_optimization' | 'reorder_suggestion' | 'process_improvement'; title: string; description: string; proposed_action: any; confidence: number; reasoning: string; data_source: any; status: 'pending' | 'approved' | 'rejected' | 'expired'; created_at: string; created_by: 'ai_assistant' | 'mcp_assistant'; expires_at: string; mcp_used?: boolean; } interface ApprovalRequest { proposal_id: string; human_decision: 'approve' | 'reject'; human_notes?: string; approved_by: string; approved_at: string; } class EnhancedAIAssistantService { /** * Main AI Assistant - analyzes data and proposes helpful actions * Enhanced with MCP server integration for reliability */ async analyzeAndPropose(): Promise<AIProposal[]> { console.log('🤖 Enhanced AI Assistant analyzing business data for improvement opportunities...'); const proposals: AIProposal[] = []; try { // Check MCP server health first const mcpHealth = await mcpIntegration.healthCheck(); console.log(`🔗 MCP server status: ${mcpHealth.healthy ? 'healthy' : 'unhealthy'} (${mcpHealth.latency}ms)`); // Use MCP for comprehensive analysis if available if (mcpHealth.healthy) { const mcpProposals = await this.getMCPProposals(); if (mcpProposals.length > 0) { proposals.push(...mcpProposals); console.log(`✨ MCP generated ${mcpProposals.length} proposals`); } } // Always run traditional analysis for comparison/fallback const traditionalProposals = await this.getTraditionalProposals(); proposals.push(...traditionalProposals); console.log(`🔧 Traditional analysis generated ${traditionalProposals.length} proposals`); // Remove duplicates (prefer MCP proposals) const uniqueProposals = this.deduplicateProposals(proposals); // Store all proposals for human review await this.storeProposals(uniqueProposals); console.log(`✅ Enhanced AI Assistant generated ${uniqueProposals.length} improvement proposals`); return uniqueProposals; } catch (error) { console.error('❌ Enhanced AI Assistant analysis failed:', error); return []; } } /** * Get proposals using MCP server */ async getMCPProposals(): Promise<AIProposal[]> { try { // Gather business context for MCP const businessContext = await this.gatherBusinessContext(); const { proposals, usedMCP } = await mcpIntegration.getAIProposals({ context: businessContext, analysis_type: 'comprehensive', include_confidence: true, max_proposals: 10 }); if (!usedMCP || !proposals) { console.warn('MCP proposals failed, falling back to traditional'); return []; } // Convert MCP proposals to our format return proposals.map((mcpProposal: any, index: number) => ({ id: `mcp_${Date.now()}_${index}`, type: this.mapMCPProposalType(mcpProposal.type), title: mcpProposal.title || 'MCP Proposal', description: mcpProposal.description || 'AI-generated proposal via MCP', proposed_action: mcpProposal.action, confidence: mcpProposal.confidence || 80, reasoning: mcpProposal.reasoning || 'Generated by MCP server', data_source: mcpProposal.data_source, status: 'pending', created_at: new Date().toISOString(), created_by: 'mcp_assistant', expires_at: this.getExpiryDate(7), mcp_used: true })); } catch (error) { console.warn('MCP proposals generation failed:', error); return []; } } /** * Get proposals using traditional methods (fallback) */ async getTraditionalProposals(): Promise<AIProposal[]> { const proposals: AIProposal[] = []; try { // Check for uncategorized expenses const expenseProposals = await this.proposeExpenseCategorization(); proposals.push(...expenseProposals); // Check for stock issues const stockProposals = await this.proposeStockAdjustments(); proposals.push(...stockProposals); // Check for pricing opportunities const priceProposals = await this.proposePriceOptimizations(); proposals.push(...priceProposals); // Check for process improvements const processProposals = await this.proposeProcessImprovements(); proposals.push(...processProposals); return proposals; } catch (error) { console.error('Traditional proposals failed:', error); return []; } } /** * Enhanced expense categorization with MCP fallback */ async proposeExpenseCategorization(): Promise<AIProposal[]> { const proposals: AIProposal[] = []; try { // Get uncategorized expenses const { data: uncategorizedExpenses } = await supabase .from('expenses') .select('*') .or('category.is.null,category.eq.""') .limit(10); if (!uncategorizedExpenses || uncategorizedExpenses.length === 0) { return proposals; } for (const expense of uncategorizedExpenses) { let categorization; let usedMCP = false; // Try MCP first if (mcpIntegration.isAvailable()) { const mcpResult = await mcpIntegration.callTool('analyze_expense', { expense_data: expense, operation: 'categorize' }); if (mcpResult.success) { categorization = mcpResult.data; usedMCP = true; } } // Fallback to traditional method if (!categorization) { categorization = await this.suggestExpenseCategory(expense); } if (categorization && categorization.confidence > 70) { proposals.push({ id: `exp_cat_${expense.id}_${Date.now()}`, type: 'expense_categorization', title: `Categorize "${expense.description}"`, description: `AI suggests categorizing this ₱${expense.amount} expense as "${categorization.category}"`, proposed_action: { expense_id: expense.id, new_category: categorization.category, confidence: categorization.confidence }, confidence: categorization.confidence, reasoning: categorization.reasoning, data_source: expense, status: 'pending', created_at: new Date().toISOString(), created_by: usedMCP ? 'mcp_assistant' : 'ai_assistant', expires_at: this.getExpiryDate(7), mcp_used: usedMCP }); } } return proposals; } catch (error) { console.warn('Expense categorization proposals failed:', error); return []; } } /** * Enhanced stock analysis with MCP integration */ async proposeStockAdjustments(): Promise<AIProposal[]> { const proposals: AIProposal[] = []; try { // Get current stock and sales data const [{ data: products }, { data: recentSales }] = await Promise.all([ supabase.from('products').select('*'), supabase.from('sales').select('*') .gte('date', this.getDaysAgo(30)) .order('date', { ascending: false }) ]); if (!products) return proposals; let stockAnalysis; let usedMCP = false; // Try MCP first for comprehensive analysis if (mcpIntegration.isAvailable()) { const mcpResult = await mcpIntegration.applyStockPattern('reorder_analysis', { products, sales_data: recentSales || [], timeframe: '30d' }); if (mcpResult.success) { stockAnalysis = mcpResult.result; usedMCP = true; } } // Fallback to traditional analysis if (!stockAnalysis) { stockAnalysis = await this.analyzeStockNeeds(products, recentSales || []); } for (const suggestion of stockAnalysis.suggestions || []) { if (suggestion.confidence > 75) { proposals.push({ id: `stock_adj_${suggestion.product_id}_${Date.now()}`, type: 'stock_adjustment', title: `${suggestion.action} ${suggestion.product_name}`, description: suggestion.description, proposed_action: suggestion, confidence: suggestion.confidence, reasoning: suggestion.reasoning, data_source: { products, sales: recentSales }, status: 'pending', created_at: new Date().toISOString(), created_by: usedMCP ? 'mcp_assistant' : 'ai_assistant', expires_at: this.getExpiryDate(3), mcp_used: usedMCP }); } } return proposals; } catch (error) { console.warn('Stock adjustment proposals failed:', error); return []; } } /** * Business context gathering for MCP */ async gatherBusinessContext(): Promise<any> { try { const [ { data: recentSales }, { data: recentExpenses }, { data: products }, { data: recentNotes } ] = await Promise.all([ supabase.from('sales').select('*').gte('date', this.getDaysAgo(30)).limit(100), supabase.from('expenses').select('*').gte('date', this.getDaysAgo(30)).limit(100), supabase.from('products').select('*'), supabase.from('notes').select('*').gte('created_at', this.getDaysAgo(7)).limit(50) ]); return { recent_sales: recentSales || [], recent_expenses: recentExpenses || [], products: products || [], recent_notes: recentNotes || [], timeframe: '30d', business_type: 'chicken_processing' }; } catch (error) { console.warn('Failed to gather business context:', error); return {}; } } /** * Remove duplicate proposals, preferring MCP ones */ deduplicateProposals(proposals: AIProposal[]): AIProposal[] { const seen = new Map<string, AIProposal>(); for (const proposal of proposals) { const key = `${proposal.type}_${proposal.title}`; const existing = seen.get(key); if (!existing || proposal.mcp_used) { seen.set(key, proposal); } } return Array.from(seen.values()); } /** * Map MCP proposal types to our internal types */ mapMCPProposalType(mcpType: string): AIProposal['type'] { const mapping: Record<string, AIProposal['type']> = { 'expense_categorization': 'expense_categorization', 'stock_adjustment': 'stock_adjustment', 'reorder_suggestion': 'reorder_suggestion', 'price_optimization': 'price_optimization', 'process_improvement': 'process_improvement' }; return mapping[mcpType] || 'process_improvement'; } // Traditional methods remain unchanged for fallback async suggestExpenseCategory(expense: any): Promise<any> { // Existing implementation... return null; } async analyzeStockNeeds(products: any[], sales: any[]): Promise<any> { // Existing implementation... return { suggestions: [] }; } async proposePriceOptimizations(): Promise<AIProposal[]> { // Existing implementation... return []; } async proposeProcessImprovements(): Promise<AIProposal[]> { // Existing implementation... return []; } async storeProposals(proposals: AIProposal[]): Promise<void> { // Store proposals in database with MCP tracking for (const proposal of proposals) { await supabase.from('ai_proposals').insert({ ...proposal, metadata: { mcp_used: proposal.mcp_used, created_by: proposal.created_by } }); } } getDaysAgo(days: number): string { const date = new Date(); date.setDate(date.getDate() - days); return date.toISOString(); } getExpiryDate(days: number): string { const date = new Date(); date.setDate(date.getDate() + days); return date.toISOString(); } } // Export enhanced service export const enhancedAIAssistant = new EnhancedAIAssistantService(); // Backward compatibility - export original interface export { AIProposal, ApprovalRequest };

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/PSYGER02/mcpserver'

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