Skip to main content
Glama
sigaihealth

RealVest Real Estate MCP Server

breakeven.js26 kB
export class BreakevenCalculator { constructor() { this.name = 'Breakeven Analysis Calculator'; this.description = 'Calculate breakeven points for real estate investments'; } getSchema() { return { type: 'object', properties: { property_costs: { type: 'object', description: 'Fixed and variable property costs', properties: { purchase_price: { type: 'number', description: 'Total property purchase price', minimum: 0 }, renovation_costs: { type: 'number', description: 'Initial renovation/improvement costs', minimum: 0, default: 0 }, closing_costs: { type: 'number', description: 'Purchase closing costs', minimum: 0, default: 0 }, down_payment: { type: 'number', description: 'Down payment amount', minimum: 0 } }, required: ['purchase_price', 'down_payment'] }, fixed_costs: { type: 'object', description: 'Monthly fixed costs', properties: { mortgage_payment: { type: 'number', description: 'Monthly mortgage payment (P&I)', minimum: 0, default: 0 }, property_tax: { type: 'number', description: 'Monthly property tax', minimum: 0, default: 0 }, insurance: { type: 'number', description: 'Monthly insurance premium', minimum: 0, default: 0 }, hoa_fees: { type: 'number', description: 'Monthly HOA fees', minimum: 0, default: 0 }, property_management: { type: 'number', description: 'Monthly property management fee', minimum: 0, default: 0 } } }, variable_costs: { type: 'object', description: 'Variable costs (per unit or percentage)', properties: { utilities_per_unit: { type: 'number', description: 'Monthly utilities per occupied unit', minimum: 0, default: 0 }, maintenance_percent: { type: 'number', description: 'Maintenance as % of rental income', minimum: 0, maximum: 30, default: 5 }, vacancy_rate: { type: 'number', description: 'Expected vacancy rate (%)', minimum: 0, maximum: 50, default: 5 }, management_percent: { type: 'number', description: 'Property management as % of rent (if not fixed)', minimum: 0, maximum: 20, default: 0 } } }, revenue_streams: { type: 'object', description: 'Property revenue sources', properties: { monthly_rent_per_unit: { type: 'number', description: 'Monthly rent per unit', minimum: 0 }, total_units: { type: 'number', description: 'Total number of rentable units', minimum: 1, default: 1 }, other_monthly_income: { type: 'number', description: 'Other monthly income (parking, laundry, etc.)', minimum: 0, default: 0 }, annual_rent_increase: { type: 'number', description: 'Expected annual rent increase (%)', minimum: 0, maximum: 20, default: 3 } }, required: ['monthly_rent_per_unit'] }, analysis_parameters: { type: 'object', description: 'Analysis parameters', properties: { target_cash_flow: { type: 'number', description: 'Target monthly cash flow', minimum: 0, default: 0 }, analysis_period_years: { type: 'number', description: 'Years to analyze', minimum: 1, maximum: 30, default: 10 }, include_appreciation: { type: 'boolean', description: 'Include property appreciation in ROI', default: false }, appreciation_rate: { type: 'number', description: 'Annual appreciation rate (%)', minimum: 0, maximum: 20, default: 3 } } } }, required: ['property_costs', 'revenue_streams'] }; } calculate(params) { const { property_costs, fixed_costs = {}, variable_costs = {}, revenue_streams, analysis_parameters = {} } = params; // Calculate total initial investment const total_initial_investment = this.calculateInitialInvestment(property_costs); // Calculate monthly fixed costs const monthly_fixed_costs = this.calculateMonthlyFixedCosts(fixed_costs); // Calculate breakeven occupancy const breakeven_occupancy = this.calculateBreakevenOccupancy( revenue_streams, monthly_fixed_costs, variable_costs ); // Calculate breakeven rent const breakeven_rent = this.calculateBreakevenRent( monthly_fixed_costs, variable_costs, revenue_streams ); // Calculate time to positive cash flow const time_to_positive_cashflow = this.calculateTimeToPositiveCashflow( total_initial_investment, revenue_streams, monthly_fixed_costs, variable_costs ); // Calculate ROI breakeven const roi_breakeven = this.calculateROIBreakeven( total_initial_investment, revenue_streams, monthly_fixed_costs, variable_costs, analysis_parameters ); // Sensitivity analysis const sensitivity = this.performSensitivityAnalysis( revenue_streams, monthly_fixed_costs, variable_costs, breakeven_occupancy.occupancy_rate ); // Multi-year projection const projection = this.createMultiYearProjection( revenue_streams, monthly_fixed_costs, variable_costs, analysis_parameters, total_initial_investment ); // Target analysis const target_analysis = this.analyzeTargetCashFlow( revenue_streams, monthly_fixed_costs, variable_costs, analysis_parameters.target_cash_flow || 0 ); // Risk assessment const risk_assessment = this.assessRisk( breakeven_occupancy.occupancy_rate, sensitivity, revenue_streams ); return { initial_investment: { down_payment: property_costs.down_payment, closing_costs: property_costs.closing_costs || 0, renovation_costs: property_costs.renovation_costs || 0, total_cash_required: parseFloat(total_initial_investment.toFixed(2)) }, cost_analysis: { monthly_fixed_costs: parseFloat(monthly_fixed_costs.toFixed(2)), fixed_cost_breakdown: this.formatCostBreakdown(fixed_costs), variable_cost_factors: { maintenance_rate: variable_costs.maintenance_percent || 5, vacancy_rate: variable_costs.vacancy_rate || 5, management_rate: variable_costs.management_percent || 0 } }, breakeven_analysis: { occupancy_breakeven: breakeven_occupancy, rent_breakeven: breakeven_rent, time_to_positive_cashflow: time_to_positive_cashflow, roi_breakeven: roi_breakeven }, current_performance: this.calculateCurrentPerformance( revenue_streams, monthly_fixed_costs, variable_costs ), sensitivity_analysis: sensitivity, target_analysis: target_analysis, multi_year_projection: projection, risk_assessment: risk_assessment, recommendations: this.generateRecommendations( breakeven_occupancy.occupancy_rate, time_to_positive_cashflow, risk_assessment, target_analysis ) }; } calculateInitialInvestment(costs) { return costs.down_payment + (costs.closing_costs || 0) + (costs.renovation_costs || 0); } calculateMonthlyFixedCosts(fixed) { return Object.values(fixed).reduce((sum, cost) => sum + (cost || 0), 0); } calculateBreakevenOccupancy(revenue, fixedCosts, variableCosts) { const rentPerUnit = revenue.monthly_rent_per_unit; const totalUnits = revenue.total_units || 1; const otherIncome = revenue.other_monthly_income || 0; // Variable costs as percentage of revenue const maintenanceRate = (variableCosts.maintenance_percent || 5) / 100; const managementRate = (variableCosts.management_percent || 0) / 100; const utilitiesPerUnit = variableCosts.utilities_per_unit || 0; // Net revenue per occupied unit after variable costs const netRevenuePerUnit = rentPerUnit * (1 - maintenanceRate - managementRate) - utilitiesPerUnit; // Units needed to cover fixed costs const unitsNeeded = (fixedCosts - otherIncome) / netRevenuePerUnit; const occupancyRate = (unitsNeeded / totalUnits) * 100; return { occupancy_rate: parseFloat(Math.min(100, occupancyRate).toFixed(1)), units_needed: parseFloat(unitsNeeded.toFixed(2)), total_units: totalUnits, feasible: occupancyRate <= 100, margin: parseFloat((100 - occupancyRate).toFixed(1)) }; } calculateBreakevenRent(fixedCosts, variableCosts, revenue) { const totalUnits = revenue.total_units || 1; const otherIncome = revenue.other_monthly_income || 0; const targetOccupancy = 1 - (variableCosts.vacancy_rate || 5) / 100; const maintenanceRate = (variableCosts.maintenance_percent || 5) / 100; const managementRate = (variableCosts.management_percent || 0) / 100; const utilitiesPerUnit = variableCosts.utilities_per_unit || 0; // Rent needed per unit to break even const effectiveUnits = totalUnits * targetOccupancy; const revenueNeeded = fixedCosts - otherIncome + (utilitiesPerUnit * effectiveUnits); const rentBeforeVariableCosts = revenueNeeded / effectiveUnits; const breakevenRent = rentBeforeVariableCosts / (1 - maintenanceRate - managementRate); const currentRent = revenue.monthly_rent_per_unit; const difference = breakevenRent - currentRent; const percentDifference = (difference / currentRent) * 100; return { breakeven_rent: parseFloat(breakevenRent.toFixed(2)), current_rent: currentRent, difference: parseFloat(difference.toFixed(2)), percent_difference: parseFloat(percentDifference.toFixed(1)), achievable: currentRent >= breakevenRent }; } calculateTimeToPositiveCashflow(initialInvestment, revenue, fixedCosts, variableCosts) { const monthlyRent = revenue.monthly_rent_per_unit * (revenue.total_units || 1); const otherIncome = revenue.other_monthly_income || 0; const vacancyRate = (variableCosts.vacancy_rate || 5) / 100; const maintenanceRate = (variableCosts.maintenance_percent || 5) / 100; const managementRate = (variableCosts.management_percent || 0) / 100; const effectiveIncome = (monthlyRent + otherIncome) * (1 - vacancyRate); const variableExpenses = effectiveIncome * (maintenanceRate + managementRate) + (variableCosts.utilities_per_unit || 0) * (revenue.total_units || 1); const monthlyCashFlow = effectiveIncome - fixedCosts - variableExpenses; if (monthlyCashFlow <= 0) { return { months: null, years: null, monthly_cash_flow: parseFloat(monthlyCashFlow.toFixed(2)), achievable: false, explanation: "Property has negative cash flow" }; } const monthsToRecover = initialInvestment / monthlyCashFlow; return { months: Math.ceil(monthsToRecover), years: parseFloat((monthsToRecover / 12).toFixed(1)), monthly_cash_flow: parseFloat(monthlyCashFlow.toFixed(2)), achievable: true, total_to_recover: initialInvestment }; } calculateROIBreakeven(initialInvestment, revenue, fixedCosts, variableCosts, parameters) { const includeAppreciation = parameters.include_appreciation || false; const appreciationRate = (parameters.appreciation_rate || 3) / 100; const propertyValue = initialInvestment * 4; // Rough estimate let cumulativeReturn = 0; let month = 0; // Calculate monthly cash flow const monthlyRent = revenue.monthly_rent_per_unit * (revenue.total_units || 1); const otherIncome = revenue.other_monthly_income || 0; const vacancyRate = (variableCosts.vacancy_rate || 5) / 100; const effectiveIncome = (monthlyRent + otherIncome) * (1 - vacancyRate); const maintenanceRate = (variableCosts.maintenance_percent || 5) / 100; const managementRate = (variableCosts.management_percent || 0) / 100; const variableExpenses = effectiveIncome * (maintenanceRate + managementRate); const monthlyCashFlow = effectiveIncome - fixedCosts - variableExpenses; while (cumulativeReturn < initialInvestment && month < 360) { // Max 30 years month++; cumulativeReturn += monthlyCashFlow; if (includeAppreciation && month % 12 === 0) { const years = month / 12; const appreciatedValue = propertyValue * Math.pow(1 + appreciationRate, years); const appreciationGain = appreciatedValue - propertyValue; // Only count realized appreciation if we're looking at exit if (month === 60 || month === 120) { // 5 or 10 year marks cumulativeReturn += appreciationGain * 0.1; // Assume 10% of appreciation is accessible } } } const breakevenYears = month / 12; const annualizedROI = month > 0 ? (cumulativeReturn / initialInvestment / breakevenYears) * 100 : 0; return { months_to_100_percent_roi: month < 360 ? month : null, years_to_100_percent_roi: month < 360 ? parseFloat(breakevenYears.toFixed(1)) : null, achievable: month < 360, annualized_roi_at_breakeven: parseFloat(annualizedROI.toFixed(2)), includes_appreciation: includeAppreciation }; } performSensitivityAnalysis(revenue, fixedCosts, variableCosts, baseOccupancy) { const scenarios = []; // Rent sensitivity const rentChanges = [-20, -10, -5, 0, 5, 10, 20]; rentChanges.forEach(change => { const adjustedRevenue = { ...revenue, monthly_rent_per_unit: revenue.monthly_rent_per_unit * (1 + change / 100) }; const result = this.calculateBreakevenOccupancy(adjustedRevenue, fixedCosts, variableCosts); scenarios.push({ variable: 'Rent', change: `${change > 0 ? '+' : ''}${change}%`, breakeven_occupancy: result.occupancy_rate, impact: parseFloat((result.occupancy_rate - baseOccupancy).toFixed(1)) }); }); // Fixed cost sensitivity const costChanges = [-20, -10, 0, 10, 20, 30]; costChanges.forEach(change => { const adjustedFixed = fixedCosts * (1 + change / 100); const result = this.calculateBreakevenOccupancy(revenue, adjustedFixed, variableCosts); scenarios.push({ variable: 'Fixed Costs', change: `${change > 0 ? '+' : ''}${change}%`, breakeven_occupancy: result.occupancy_rate, impact: parseFloat((result.occupancy_rate - baseOccupancy).toFixed(1)) }); }); // Find most sensitive variable const rentSensitivity = Math.abs(scenarios.find(s => s.variable === 'Rent' && s.change === '+10%').impact); const costSensitivity = Math.abs(scenarios.find(s => s.variable === 'Fixed Costs' && s.change === '+10%').impact); return { scenarios: scenarios, most_sensitive_to: rentSensitivity > costSensitivity ? 'Rent Changes' : 'Cost Changes', rent_elasticity: parseFloat((rentSensitivity / 10).toFixed(2)), // % change in breakeven per 1% rent change cost_elasticity: parseFloat((costSensitivity / 10).toFixed(2)) }; } calculateCurrentPerformance(revenue, fixedCosts, variableCosts) { const monthlyRent = revenue.monthly_rent_per_unit * (revenue.total_units || 1); const otherIncome = revenue.other_monthly_income || 0; const grossIncome = monthlyRent + otherIncome; const vacancyRate = (variableCosts.vacancy_rate || 5) / 100; const effectiveIncome = grossIncome * (1 - vacancyRate); const maintenanceRate = (variableCosts.maintenance_percent || 5) / 100; const managementRate = (variableCosts.management_percent || 0) / 100; const variableExpenses = effectiveIncome * (maintenanceRate + managementRate) + (variableCosts.utilities_per_unit || 0) * (revenue.total_units || 1); const totalExpenses = fixedCosts + variableExpenses; const noi = effectiveIncome - totalExpenses; const operatingMargin = (noi / effectiveIncome) * 100; return { gross_monthly_income: parseFloat(grossIncome.toFixed(2)), effective_monthly_income: parseFloat(effectiveIncome.toFixed(2)), total_monthly_expenses: parseFloat(totalExpenses.toFixed(2)), net_operating_income: parseFloat(noi.toFixed(2)), operating_margin: parseFloat(operatingMargin.toFixed(1)), expense_ratio: parseFloat(((totalExpenses / effectiveIncome) * 100).toFixed(1)) }; } createMultiYearProjection(revenue, fixedCosts, variableCosts, parameters, initialInvestment) { const years = parameters.analysis_period_years || 10; const rentGrowth = (revenue.annual_rent_increase || 3) / 100; const expenseGrowth = 0.025; // 2.5% expense growth const projection = []; let currentRent = revenue.monthly_rent_per_unit; let currentFixed = fixedCosts; let cumulativeCashFlow = -initialInvestment; for (let year = 1; year <= years; year++) { if (year > 1) { currentRent *= (1 + rentGrowth); currentFixed *= (1 + expenseGrowth); } const annualRent = currentRent * (revenue.total_units || 1) * 12; const annualOther = (revenue.other_monthly_income || 0) * 12; const vacancyLoss = annualRent * ((variableCosts.vacancy_rate || 5) / 100); const effectiveIncome = annualRent + annualOther - vacancyLoss; const annualFixed = currentFixed * 12; const annualVariable = effectiveIncome * ((variableCosts.maintenance_percent || 5) / 100 + (variableCosts.management_percent || 0) / 100); const annualCashFlow = effectiveIncome - annualFixed - annualVariable; cumulativeCashFlow += annualCashFlow; projection.push({ year: year, annual_income: parseFloat(effectiveIncome.toFixed(2)), annual_expenses: parseFloat((annualFixed + annualVariable).toFixed(2)), annual_cash_flow: parseFloat(annualCashFlow.toFixed(2)), cumulative_cash_flow: parseFloat(cumulativeCashFlow.toFixed(2)), roi_to_date: parseFloat(((cumulativeCashFlow / initialInvestment) * 100).toFixed(2)) }); } return projection; } analyzeTargetCashFlow(revenue, fixedCosts, variableCosts, targetCashFlow) { if (targetCashFlow === 0) { return null; } // Calculate current cash flow const current = this.calculateCurrentPerformance(revenue, fixedCosts, variableCosts); const currentCashFlow = current.net_operating_income; const gap = targetCashFlow - currentCashFlow; if (currentCashFlow >= targetCashFlow) { return { target_achieved: true, current_cash_flow: currentCashFlow, target_cash_flow: targetCashFlow, surplus: parseFloat((currentCashFlow - targetCashFlow).toFixed(2)) }; } // Calculate what's needed to reach target const rentIncrease = (gap / ((revenue.total_units || 1) * (1 - (variableCosts.vacancy_rate || 5) / 100))) / (1 - (variableCosts.maintenance_percent || 5) / 100 - (variableCosts.management_percent || 0) / 100); const rentIncreasePercent = (rentIncrease / revenue.monthly_rent_per_unit) * 100; // Or expense reduction needed const expenseReduction = gap; const expenseReductionPercent = (expenseReduction / (fixedCosts + current.total_monthly_expenses - fixedCosts)) * 100; return { target_achieved: false, current_cash_flow: currentCashFlow, target_cash_flow: targetCashFlow, gap: parseFloat(gap.toFixed(2)), rent_increase_needed: parseFloat(rentIncrease.toFixed(2)), rent_increase_percent: parseFloat(rentIncreasePercent.toFixed(1)), expense_reduction_needed: parseFloat(expenseReduction.toFixed(2)), expense_reduction_percent: parseFloat(expenseReductionPercent.toFixed(1)) }; } assessRisk(breakevenOccupancy, sensitivity, revenue) { const riskFactors = []; let riskScore = 0; // Occupancy risk if (breakevenOccupancy > 90) { riskFactors.push({ factor: 'High Breakeven Occupancy', severity: 'High', description: 'Little margin for vacancy' }); riskScore += 3; } else if (breakevenOccupancy > 80) { riskFactors.push({ factor: 'Moderate Breakeven Occupancy', severity: 'Medium', description: 'Limited vacancy cushion' }); riskScore += 2; } // Sensitivity risk if (sensitivity.rent_elasticity > 1.5) { riskFactors.push({ factor: 'High Rent Sensitivity', severity: 'High', description: 'Small rent changes have large impact' }); riskScore += 2; } // Concentration risk if ((revenue.total_units || 1) === 1) { riskFactors.push({ factor: 'Single Unit Risk', severity: 'Medium', description: 'All income from one tenant' }); riskScore += 2; } let overallRisk; if (riskScore >= 5) { overallRisk = 'High Risk'; } else if (riskScore >= 3) { overallRisk = 'Moderate Risk'; } else { overallRisk = 'Low Risk'; } return { overall_risk: overallRisk, risk_score: riskScore, risk_factors: riskFactors, breakeven_margin: parseFloat((100 - breakevenOccupancy).toFixed(1)) }; } formatCostBreakdown(costs) { const breakdown = []; const costNames = { mortgage_payment: 'Mortgage Payment', property_tax: 'Property Tax', insurance: 'Insurance', hoa_fees: 'HOA Fees', property_management: 'Property Management' }; const total = Object.values(costs).reduce((sum, cost) => sum + (cost || 0), 0); Object.entries(costs).forEach(([key, value]) => { if (value > 0) { breakdown.push({ category: costNames[key] || key, monthly_amount: value, annual_amount: value * 12, percentage: total > 0 ? parseFloat(((value / total) * 100).toFixed(1)) : 0 }); } }); return breakdown.sort((a, b) => b.monthly_amount - a.monthly_amount); } generateRecommendations(breakevenOccupancy, timeToPositive, riskAssessment, targetAnalysis) { const recommendations = []; // Breakeven occupancy recommendations if (breakevenOccupancy > 90) { recommendations.push({ type: 'Warning', category: 'Occupancy', message: `High breakeven occupancy of ${breakevenOccupancy}%`, action: 'Consider reducing costs or increasing rents to improve margin' }); } else if (breakevenOccupancy < 70) { recommendations.push({ type: 'Positive', category: 'Occupancy', message: `Strong margin with ${breakevenOccupancy}% breakeven`, action: 'Good cushion for market downturns' }); } // Time to positive cash flow if (!timeToPositive.achievable) { recommendations.push({ type: 'Critical', category: 'Cash Flow', message: 'Property has negative cash flow', action: 'Restructure financing or improve revenue to achieve positive flow' }); } else if (timeToPositive.years > 5) { recommendations.push({ type: 'Caution', category: 'ROI Timeline', message: `Long ${timeToPositive.years} year payback period`, action: 'Consider if you have sufficient liquidity for this timeline' }); } // Risk recommendations if (riskAssessment.overall_risk === 'High Risk') { recommendations.push({ type: 'Risk Alert', category: 'Overall Risk', message: 'Multiple high-risk factors identified', action: 'Build larger reserves and have contingency plans' }); } // Target achievement if (targetAnalysis && !targetAnalysis.target_achieved) { if (targetAnalysis.rent_increase_percent < 10) { recommendations.push({ type: 'Opportunity', category: 'Target Achievement', message: `Only ${targetAnalysis.rent_increase_percent}% rent increase needed`, action: 'Target is achievable with modest rent growth' }); } } // General optimization recommendations.push({ type: 'Best Practice', category: 'Optimization', message: 'Regular review of expenses and rents', action: 'Annual analysis to maintain healthy margins' }); return recommendations; } }

Latest Blog Posts

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/sigaihealth/realvestmcp'

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