UNPKG

ms365-mcp-server

Version:

Microsoft 365 MCP Server for managing Microsoft 365 email through natural language interactions with full OAuth2 authentication support

391 lines (390 loc) 14.6 kB
import { logger } from './api.js'; export var EmailCategory; (function (EmailCategory) { EmailCategory["GOVERNMENT"] = "government"; EmailCategory["TAX"] = "tax"; EmailCategory["LEGAL"] = "legal"; EmailCategory["FINANCIAL"] = "financial"; EmailCategory["HEALTHCARE"] = "healthcare"; EmailCategory["INSURANCE"] = "insurance"; EmailCategory["DEADLINE"] = "deadline"; EmailCategory["INVOICE"] = "invoice"; EmailCategory["CONTRACT"] = "contract"; EmailCategory["SECURITY"] = "security"; EmailCategory["COMPLIANCE"] = "compliance"; EmailCategory["NOTIFICATION"] = "notification"; EmailCategory["SPAM"] = "spam"; EmailCategory["PERSONAL"] = "personal"; EmailCategory["BUSINESS"] = "business"; EmailCategory["URGENT"] = "urgent"; EmailCategory["AUTOMATED"] = "automated"; })(EmailCategory || (EmailCategory = {})); export class ProactiveIntelligence { constructor(ms365Operations) { this.ms365Operations = ms365Operations; } /** * Classify a single email */ classifyEmail(email) { const matchedRules = []; const categories = []; const reasons = []; let maxPriority = 'low'; let totalConfidence = 0; for (const rule of ProactiveIntelligence.CLASSIFICATION_RULES) { const match = this.evaluateRule(email, rule); if (match.isMatch) { matchedRules.push(rule.id); categories.push(rule.category); reasons.push(match.reason); totalConfidence += match.confidence; // Update priority if (this.getPriorityScore(rule.priority) > this.getPriorityScore(maxPriority)) { maxPriority = rule.priority; } } } const averageConfidence = matchedRules.length > 0 ? totalConfidence / matchedRules.length : 0; const actions = this.generateActions(categories, maxPriority); return { email, categories, priority: maxPriority, confidence: averageConfidence, matchedRules, reasons, actions }; } /** * Evaluate a classification rule against an email */ evaluateRule(email, rule) { let matches = 0; let totalChecks = 0; const matchDetails = []; const emailText = { senderDomain: email.from.address.split('@')[1]?.toLowerCase() || '', senderName: email.from.name.toLowerCase(), subject: email.subject.toLowerCase(), body: email.bodyPreview.toLowerCase(), combined: `${email.from.name} ${email.subject} ${email.bodyPreview}`.toLowerCase() }; // Check sender domains if (rule.patterns.senderDomains) { totalChecks++; for (const domain of rule.patterns.senderDomains) { if (emailText.senderDomain.includes(domain.toLowerCase())) { matches++; matchDetails.push(`sender domain: ${domain}`); break; } } } // Check sender names if (rule.patterns.senderNames) { totalChecks++; for (const name of rule.patterns.senderNames) { if (emailText.senderName.includes(name.toLowerCase())) { matches++; matchDetails.push(`sender name: ${name}`); break; } } } // Check subject keywords if (rule.patterns.subjectKeywords) { totalChecks++; for (const keyword of rule.patterns.subjectKeywords) { if (emailText.subject.includes(keyword.toLowerCase())) { matches++; matchDetails.push(`subject keyword: ${keyword}`); break; } } } // Check body keywords if (rule.patterns.bodyKeywords) { totalChecks++; for (const keyword of rule.patterns.bodyKeywords) { if (emailText.body.includes(keyword.toLowerCase())) { matches++; matchDetails.push(`body keyword: ${keyword}`); break; } } } // Check combined keywords if (rule.patterns.combinedKeywords) { totalChecks++; for (const keyword of rule.patterns.combinedKeywords) { if (emailText.combined.includes(keyword.toLowerCase())) { matches++; matchDetails.push(`combined keyword: ${keyword}`); break; } } } // Determine if rule matches let isMatch = false; const confidence = totalChecks > 0 ? matches / totalChecks : 0; if (rule.conditions.matchType === 'any') { isMatch = matches > 0; } else if (rule.conditions.matchType === 'all') { isMatch = matches === totalChecks; } if (rule.conditions.minimumMatches) { isMatch = matches >= rule.conditions.minimumMatches; } if (rule.conditions.confidenceThreshold) { isMatch = isMatch && confidence >= rule.conditions.confidenceThreshold; } return { isMatch, confidence, reason: `${rule.name}: ${matchDetails.join(', ')}` }; } /** * Get priority score for comparison */ getPriorityScore(priority) { switch (priority) { case 'critical': return 4; case 'high': return 3; case 'medium': return 2; case 'low': return 1; default: return 0; } } /** * Generate recommended actions based on classification */ generateActions(categories, priority) { const actions = []; if (priority === 'critical') { actions.push('Mark as high priority'); actions.push('Add to urgent folder'); } if (categories.includes(EmailCategory.GOVERNMENT)) { actions.push('File in government folder'); actions.push('Set reminder for response'); } if (categories.includes(EmailCategory.TAX)) { actions.push('File in tax documents'); actions.push('Check for deadline'); } if (categories.includes(EmailCategory.DEADLINE)) { actions.push('Set calendar reminder'); actions.push('Flag for follow-up'); } if (categories.includes(EmailCategory.LEGAL)) { actions.push('File in legal folder'); actions.push('Consider legal review'); } if (categories.includes(EmailCategory.FINANCIAL)) { actions.push('File in financial folder'); actions.push('Verify sender authenticity'); } return actions; } /** * Batch classify multiple emails */ async batchClassifyEmails(emails) { const results = new Map(); logger.log(`🎯 Classifying ${emails.length} emails`); for (const email of emails) { try { const classification = this.classifyEmail(email); results.set(email.id, classification); } catch (error) { logger.error(`Error classifying email ${email.id}:`, error); } } const criticalEmails = Array.from(results.values()).filter(r => r.priority === 'critical').length; const highPriorityEmails = Array.from(results.values()).filter(r => r.priority === 'high').length; logger.log(`🎯 Classification complete: ${criticalEmails} critical, ${highPriorityEmails} high priority`); return results; } /** * Get emails by category */ getEmailsByCategory(classifications, category) { return Array.from(classifications.values()) .filter(result => result.categories.includes(category)) .sort((a, b) => this.getPriorityScore(b.priority) - this.getPriorityScore(a.priority)); } /** * Get high priority emails */ getHighPriorityEmails(classifications) { return Array.from(classifications.values()) .filter(result => result.priority === 'critical' || result.priority === 'high') .sort((a, b) => this.getPriorityScore(b.priority) - this.getPriorityScore(a.priority)); } /** * Generate classification summary */ generateClassificationSummary(classifications) { const results = Array.from(classifications.values()); const byPriority = { critical: results.filter(r => r.priority === 'critical').length, high: results.filter(r => r.priority === 'high').length, medium: results.filter(r => r.priority === 'medium').length, low: results.filter(r => r.priority === 'low').length }; const categoryCount = new Map(); const reasonCount = new Map(); const actionCount = new Map(); for (const result of results) { // Count categories for (const category of result.categories) { categoryCount.set(category, (categoryCount.get(category) || 0) + 1); } // Count reasons for (const reason of result.reasons) { reasonCount.set(reason, (reasonCount.get(reason) || 0) + 1); } // Count actions for (const action of result.actions) { actionCount.set(action, (actionCount.get(action) || 0) + 1); } } const byCategory = Object.fromEntries(categoryCount); const topReasons = Array.from(reasonCount.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 10) .map(([reason]) => reason); const recommendedActions = Array.from(actionCount.entries()) .sort((a, b) => b[1] - a[1]) .slice(0, 10) .map(([action]) => action); return { totalEmails: results.length, byPriority, byCategory, topReasons, recommendedActions }; } } ProactiveIntelligence.CLASSIFICATION_RULES = [ // Government emails { id: 'gov_federal', name: 'Federal Government', category: EmailCategory.GOVERNMENT, priority: 'critical', patterns: { senderDomains: ['.gov', '.mil', 'irs.gov', 'ssa.gov', 'treasury.gov'], senderNames: ['Internal Revenue Service', 'Social Security', 'Treasury', 'IRS'], combinedKeywords: ['federal', 'government', 'official', 'notice'] }, conditions: { matchType: 'any', confidenceThreshold: 0.8 } }, // Tax notices { id: 'tax_notice', name: 'Tax Notice', category: EmailCategory.TAX, priority: 'critical', patterns: { subjectKeywords: ['tax', 'irs', 'notice', 'refund', 'audit', 'filing'], bodyKeywords: ['tax return', 'refund', 'audit', 'tax due', 'payment'], senderDomains: ['irs.gov', 'treasury.gov'] }, conditions: { matchType: 'any', minimumMatches: 2 } }, // Legal documents { id: 'legal_doc', name: 'Legal Document', category: EmailCategory.LEGAL, priority: 'high', patterns: { subjectKeywords: ['legal', 'court', 'lawsuit', 'summons', 'subpoena'], bodyKeywords: ['attorney', 'lawyer', 'court', 'legal action', 'litigation'], senderNames: ['Attorney', 'Legal', 'Court', 'Law Firm'] }, conditions: { matchType: 'any', minimumMatches: 1 } }, // Financial institutions { id: 'financial_inst', name: 'Financial Institution', category: EmailCategory.FINANCIAL, priority: 'high', patterns: { senderDomains: ['bank', 'credit', 'financial', 'investment'], subjectKeywords: ['account', 'statement', 'balance', 'transaction'], bodyKeywords: ['account number', 'balance', 'transaction', 'payment'] }, conditions: { matchType: 'any', minimumMatches: 1 } }, // Healthcare { id: 'healthcare', name: 'Healthcare', category: EmailCategory.HEALTHCARE, priority: 'high', patterns: { senderNames: ['Hospital', 'Medical', 'Doctor', 'Clinic', 'Health'], subjectKeywords: ['appointment', 'medical', 'health', 'prescription'], bodyKeywords: ['patient', 'medical', 'health', 'appointment', 'prescription'] }, conditions: { matchType: 'any', minimumMatches: 1 } }, // Insurance { id: 'insurance', name: 'Insurance', category: EmailCategory.INSURANCE, priority: 'high', patterns: { senderNames: ['Insurance', 'Policy', 'Claims'], subjectKeywords: ['policy', 'claim', 'coverage', 'premium'], bodyKeywords: ['policy number', 'claim', 'coverage', 'premium', 'deductible'] }, conditions: { matchType: 'any', minimumMatches: 1 } }, // Deadline-sensitive { id: 'deadline', name: 'Deadline/Urgent', category: EmailCategory.DEADLINE, priority: 'critical', patterns: { subjectKeywords: ['deadline', 'due', 'expires', 'urgent', 'asap'], bodyKeywords: ['deadline', 'due date', 'expires', 'urgent', 'immediately'] }, conditions: { matchType: 'any', minimumMatches: 1 } }, // Invoices { id: 'invoice', name: 'Invoice/Bill', category: EmailCategory.INVOICE, priority: 'medium', patterns: { subjectKeywords: ['invoice', 'bill', 'payment', 'receipt'], bodyKeywords: ['invoice number', 'amount due', 'payment', 'bill'] }, conditions: { matchType: 'any', minimumMatches: 1 } }, // Security alerts { id: 'security', name: 'Security Alert', category: EmailCategory.SECURITY, priority: 'critical', patterns: { subjectKeywords: ['security', 'alert', 'breach', 'unauthorized', 'suspicious'], bodyKeywords: ['security', 'breach', 'unauthorized', 'login', 'password'] }, conditions: { matchType: 'any', minimumMatches: 1 } } ];