Skip to main content
Glama
sigaihealth

RealVest Real Estate MCP Server

airbnb-str.js23.7 kB
/** * Airbnb/STR Income Calculator * Analyzes short-term rental income potential and profitability */ export class AirbnbSTRCalculator { getSchema() { return { type: 'object', properties: { property_info: { type: 'object', properties: { purchase_price: { type: 'number', minimum: 0, description: 'Property purchase price' }, property_type: { type: 'string', enum: ['single_family', 'condo', 'townhouse', 'duplex', 'entire_building'], description: 'Type of property' }, bedrooms: { type: 'number', minimum: 1, maximum: 10, description: 'Number of bedrooms' }, bathrooms: { type: 'number', minimum: 1, maximum: 10, description: 'Number of bathrooms' }, max_guests: { type: 'number', minimum: 1, maximum: 20, description: 'Maximum guest capacity' }, location_type: { type: 'string', enum: ['urban', 'suburban', 'rural', 'beach', 'mountain', 'tourist_destination'], description: 'Location type' } }, required: ['purchase_price', 'bedrooms', 'bathrooms', 'max_guests'] }, rental_assumptions: { type: 'object', properties: { average_nightly_rate: { type: 'number', minimum: 0, description: 'Average nightly rate' }, occupancy_rate: { type: 'number', minimum: 0, maximum: 100, description: 'Expected occupancy rate (%)' }, seasonal_variation: { type: 'object', properties: { peak_months: { type: 'number', minimum: 0, maximum: 12, description: 'Number of peak season months' }, peak_rate_multiplier: { type: 'number', minimum: 1, description: 'Peak season rate multiplier' }, low_season_discount: { type: 'number', minimum: 0, maximum: 50, description: 'Low season discount (%)' } } }, cleaning_fee: { type: 'number', minimum: 0, description: 'Cleaning fee per booking' }, average_stay_length: { type: 'number', minimum: 1, maximum: 30, description: 'Average stay length (nights)' } }, required: ['average_nightly_rate', 'occupancy_rate'] }, operating_expenses: { type: 'object', properties: { platform_fees: { type: 'number', minimum: 0, maximum: 50, description: 'Platform fees (% of revenue)' }, cleaning_cost: { type: 'number', minimum: 0, description: 'Cleaning cost per booking' }, management_fee: { type: 'number', minimum: 0, maximum: 50, description: 'Management fee (% of revenue)' }, supplies_monthly: { type: 'number', minimum: 0, description: 'Monthly supplies cost' }, utilities_monthly: { type: 'number', minimum: 0, description: 'Monthly utilities cost' }, insurance_annual: { type: 'number', minimum: 0, description: 'Annual STR insurance cost' }, property_tax_annual: { type: 'number', minimum: 0, description: 'Annual property tax' }, hoa_monthly: { type: 'number', minimum: 0, description: 'Monthly HOA fees' }, maintenance_monthly: { type: 'number', minimum: 0, description: 'Monthly maintenance budget' }, marketing_monthly: { type: 'number', minimum: 0, description: 'Monthly marketing/advertising' } } }, financing: { type: 'object', properties: { down_payment_percent: { type: 'number', minimum: 0, maximum: 100, description: 'Down payment percentage' }, interest_rate: { type: 'number', minimum: 0, maximum: 30, description: 'Loan interest rate (%)' }, loan_term_years: { type: 'number', minimum: 1, maximum: 30, description: 'Loan term in years' }, closing_costs: { type: 'number', minimum: 0, description: 'Total closing costs' } } }, startup_costs: { type: 'object', properties: { furniture_budget: { type: 'number', minimum: 0, description: 'Initial furniture/furnishing budget' }, renovation_budget: { type: 'number', minimum: 0, description: 'Renovation/improvement budget' }, initial_supplies: { type: 'number', minimum: 0, description: 'Initial supplies and amenities' }, technology_setup: { type: 'number', minimum: 0, description: 'Smart locks, WiFi, tech setup' }, permits_licenses: { type: 'number', minimum: 0, description: 'Permits and licensing costs' } } }, analysis_options: { type: 'object', properties: { analysis_period_years: { type: 'number', minimum: 1, maximum: 30, description: 'Analysis period in years' }, annual_rate_increase: { type: 'number', minimum: 0, maximum: 20, description: 'Annual rate increase (%)' }, annual_expense_increase: { type: 'number', minimum: 0, maximum: 20, description: 'Annual expense increase (%)' }, vacancy_buffer: { type: 'number', minimum: 0, maximum: 50, description: 'Additional vacancy buffer (%)' } } } }, required: ['property_info', 'rental_assumptions'] }; } calculate(params) { const { property_info, rental_assumptions, operating_expenses = {}, financing = {}, startup_costs = {}, analysis_options = {} } = params; // Set defaults const down_payment_percent = financing.down_payment_percent || 25; const interest_rate = financing.interest_rate || 7.5; const loan_term_years = financing.loan_term_years || 30; const closing_costs = financing.closing_costs || property_info.purchase_price * 0.03; const analysis_years = analysis_options.analysis_period_years || 5; const rate_increase = analysis_options.annual_rate_increase || 3; const expense_increase = analysis_options.annual_expense_increase || 3; const vacancy_buffer = analysis_options.vacancy_buffer || 5; // Calculate financing details const down_payment = property_info.purchase_price * (down_payment_percent / 100); const loan_amount = property_info.purchase_price - down_payment; const monthly_payment = this.calculateMonthlyPayment(loan_amount, interest_rate / 100 / 12, loan_term_years * 12); // Calculate total startup investment const total_startup = down_payment + closing_costs + (startup_costs.furniture_budget || 0) + (startup_costs.renovation_budget || 0) + (startup_costs.initial_supplies || 0) + (startup_costs.technology_setup || 0) + (startup_costs.permits_licenses || 0); // Calculate revenue const revenue_analysis = this.calculateRevenue(rental_assumptions, vacancy_buffer); // Calculate operating expenses const expense_analysis = this.calculateOperatingExpenses( operating_expenses, revenue_analysis.annual_gross_revenue, property_info.purchase_price ); // Calculate cash flow const annual_debt_service = monthly_payment * 12; const annual_net_operating_income = revenue_analysis.annual_gross_revenue - expense_analysis.total_annual_expenses; const annual_cash_flow = annual_net_operating_income - annual_debt_service; const monthly_cash_flow = annual_cash_flow / 12; // Performance metrics const cap_rate = (annual_net_operating_income / property_info.purchase_price) * 100; const cash_on_cash_return = (annual_cash_flow / total_startup) * 100; const gross_rent_multiplier = property_info.purchase_price / revenue_analysis.annual_gross_revenue; // Compare to traditional rental const traditional_rental = this.calculateTraditionalRental(property_info, financing); // Multi-year projection const projections = this.calculateProjections( revenue_analysis, expense_analysis, annual_debt_service, rate_increase, expense_increase, analysis_years ); // Risk analysis const risk_analysis = this.performRiskAnalysis( rental_assumptions, revenue_analysis, expense_analysis, annual_cash_flow, property_info ); // Seasonal analysis const seasonal_analysis = this.calculateSeasonalAnalysis(rental_assumptions); // Break-even analysis const breakeven_analysis = this.calculateBreakeven( revenue_analysis, expense_analysis, annual_debt_service, rental_assumptions ); return { investment_summary: { total_investment: total_startup, purchase_price: property_info.purchase_price, down_payment: down_payment, loan_amount: loan_amount, startup_costs: total_startup - down_payment - closing_costs, monthly_debt_service: monthly_payment }, revenue_analysis: revenue_analysis, expense_analysis: expense_analysis, cash_flow_analysis: { annual_gross_revenue: revenue_analysis.annual_gross_revenue, annual_operating_expenses: expense_analysis.total_annual_expenses, annual_net_operating_income: annual_net_operating_income, annual_debt_service: annual_debt_service, annual_cash_flow: annual_cash_flow, monthly_cash_flow: monthly_cash_flow }, performance_metrics: { cap_rate: cap_rate, cash_on_cash_return: cash_on_cash_return, gross_rent_multiplier: gross_rent_multiplier, revenue_per_available_room: revenue_analysis.annual_gross_revenue / 365, profit_margin: (annual_cash_flow / revenue_analysis.annual_gross_revenue) * 100 }, traditional_rental_comparison: traditional_rental, projections: projections, seasonal_analysis: seasonal_analysis, risk_analysis: risk_analysis, breakeven_analysis: breakeven_analysis, recommendations: this.generateRecommendations( cash_on_cash_return, cap_rate, risk_analysis, traditional_rental, revenue_analysis, property_info ) }; } calculateMonthlyPayment(principal, monthlyRate, months) { if (monthlyRate === 0) return principal / months; return principal * monthlyRate * Math.pow(1 + monthlyRate, months) / (Math.pow(1 + monthlyRate, months) - 1); } calculateRevenue(rental_assumptions, vacancy_buffer = 0) { const { average_nightly_rate, occupancy_rate, cleaning_fee = 0, average_stay_length = 3, seasonal_variation = {} } = rental_assumptions; // Adjust occupancy for vacancy buffer const adjusted_occupancy = Math.max(0, occupancy_rate - vacancy_buffer); const occupied_nights = Math.floor((365 * adjusted_occupancy) / 100); // Calculate seasonal rates let weighted_nightly_rate = average_nightly_rate; if (seasonal_variation.peak_months) { const peak_months = seasonal_variation.peak_months; const peak_multiplier = seasonal_variation.peak_rate_multiplier || 1.5; const low_discount = seasonal_variation.low_season_discount || 20; const peak_nights = Math.floor((peak_months / 12) * occupied_nights); const regular_nights = occupied_nights - peak_nights; const peak_rate = average_nightly_rate * peak_multiplier; const low_rate = average_nightly_rate * (1 - low_discount / 100); weighted_nightly_rate = (peak_rate * peak_nights + low_rate * regular_nights) / occupied_nights; } // Calculate revenue const annual_room_revenue = occupied_nights * weighted_nightly_rate; const bookings_per_year = Math.floor(occupied_nights / average_stay_length); const annual_cleaning_revenue = bookings_per_year * cleaning_fee; const annual_gross_revenue = annual_room_revenue + annual_cleaning_revenue; return { occupied_nights_per_year: occupied_nights, bookings_per_year: bookings_per_year, average_nightly_rate: weighted_nightly_rate, annual_room_revenue: annual_room_revenue, annual_cleaning_revenue: annual_cleaning_revenue, annual_gross_revenue: annual_gross_revenue, effective_occupancy: adjusted_occupancy, revenue_per_occupied_night: weighted_nightly_rate + (cleaning_fee / average_stay_length) }; } calculateOperatingExpenses(operating_expenses, annual_revenue, property_value) { const { platform_fees = 15, cleaning_cost = 0, management_fee = 0, supplies_monthly = 200, utilities_monthly = 150, insurance_annual = property_value * 0.001, property_tax_annual = property_value * 0.012, hoa_monthly = 0, maintenance_monthly = 300, marketing_monthly = 100 } = operating_expenses; // Variable expenses (% of revenue) const platform_fee_amount = annual_revenue * (platform_fees / 100); const management_fee_amount = annual_revenue * (management_fee / 100); // Fixed monthly expenses const monthly_fixed = supplies_monthly + utilities_monthly + hoa_monthly + maintenance_monthly + marketing_monthly; const annual_fixed = monthly_fixed * 12; // Annual expenses const total_annual_expenses = platform_fee_amount + management_fee_amount + annual_fixed + insurance_annual + property_tax_annual + (cleaning_cost * 50); // Assuming 50 cleanings per year return { variable_expenses: { platform_fees: platform_fee_amount, management_fees: management_fee_amount, cleaning_costs: cleaning_cost * 50 }, fixed_expenses: { supplies: supplies_monthly * 12, utilities: utilities_monthly * 12, insurance: insurance_annual, property_tax: property_tax_annual, hoa: hoa_monthly * 12, maintenance: maintenance_monthly * 12, marketing: marketing_monthly * 12 }, total_annual_expenses: total_annual_expenses, expense_ratio: (total_annual_expenses / annual_revenue) * 100 }; } calculateTraditionalRental(property_info, financing) { // Estimate traditional rental based on property type and size const rent_per_bedroom = { single_family: 800, condo: 700, townhouse: 750, duplex: 650 }; const base_rent = (rent_per_bedroom[property_info.property_type] || 700) * property_info.bedrooms; const monthly_rent = Math.max(base_rent, property_info.purchase_price * 0.01 / 12); // 1% rule fallback const annual_rent = monthly_rent * 12; // Traditional rental expenses (typically lower) const annual_expenses = property_info.purchase_price * 0.08; // 8% of property value const annual_debt_service = this.calculateMonthlyPayment( property_info.purchase_price * (1 - (financing.down_payment_percent || 25) / 100), (financing.interest_rate || 7.5) / 100 / 12, (financing.loan_term_years || 30) * 12 ) * 12; const traditional_cash_flow = annual_rent - annual_expenses - annual_debt_service; return { estimated_monthly_rent: monthly_rent, annual_rental_income: annual_rent, annual_expenses: annual_expenses, annual_cash_flow: traditional_cash_flow, cash_on_cash_return: (traditional_cash_flow / (property_info.purchase_price * (financing.down_payment_percent || 25) / 100)) * 100 }; } calculateProjections(revenue_analysis, expense_analysis, debt_service, rate_increase, expense_increase, years) { const projections = []; let current_revenue = revenue_analysis.annual_gross_revenue; let current_expenses = expense_analysis.total_annual_expenses; for (let year = 1; year <= years; year++) { const annual_noi = current_revenue - current_expenses; const annual_cash_flow = annual_noi - debt_service; projections.push({ year: year, gross_revenue: current_revenue, operating_expenses: current_expenses, net_operating_income: annual_noi, cash_flow: annual_cash_flow, cumulative_cash_flow: projections.reduce((sum, p) => sum + p.cash_flow, annual_cash_flow) }); // Increase for next year current_revenue *= (1 + rate_increase / 100); current_expenses *= (1 + expense_increase / 100); } return projections; } calculateSeasonalAnalysis(rental_assumptions) { const { seasonal_variation } = rental_assumptions; if (!seasonal_variation || !seasonal_variation.peak_months) { return null; } const peak_months = seasonal_variation.peak_months; const shoulder_months = Math.max(0, 12 - peak_months - 4); // Assume 4 low months const low_months = 12 - peak_months - shoulder_months; const base_rate = rental_assumptions.average_nightly_rate; const peak_rate = base_rate * (seasonal_variation.peak_rate_multiplier || 1.5); const low_rate = base_rate * (1 - (seasonal_variation.low_season_discount || 20) / 100); return { peak_season: { months: peak_months, nightly_rate: peak_rate, monthly_revenue: peak_rate * 25 * (rental_assumptions.occupancy_rate / 100) // 25 nights avg }, shoulder_season: { months: shoulder_months, nightly_rate: base_rate, monthly_revenue: base_rate * 22 * (rental_assumptions.occupancy_rate / 100) }, low_season: { months: low_months, nightly_rate: low_rate, monthly_revenue: low_rate * 18 * (rental_assumptions.occupancy_rate / 100) } }; } performRiskAnalysis(rental_assumptions, revenue_analysis, expense_analysis, annual_cash_flow, property_info) { const risks = []; const opportunities = []; // Occupancy risk if (rental_assumptions.occupancy_rate > 75) { risks.push('High occupancy assumption may be optimistic'); } if (rental_assumptions.occupancy_rate < 50) { risks.push('Low occupancy rate indicates market challenges'); } // Revenue concentration risk const revenue_per_night = revenue_analysis.annual_gross_revenue / revenue_analysis.occupied_nights_per_year; if (revenue_per_night > 300) { risks.push('High nightly rate may limit demand in economic downturns'); } // Cash flow risk if (annual_cash_flow < 0) { risks.push('Negative cash flow - property loses money'); } else if (annual_cash_flow < revenue_analysis.annual_gross_revenue * 0.1) { risks.push('Thin profit margins vulnerable to expense increases'); } // Market risks if (property_info.location_type === 'tourist_destination') { risks.push('Tourism-dependent income subject to travel disruptions'); opportunities.push('High revenue potential during peak seasons'); } // Regulatory risk risks.push('Local STR regulations may change and impact operations'); // Opportunities if (expense_analysis.expense_ratio > 60) { opportunities.push('High expense ratio suggests cost optimization potential'); } if (revenue_analysis.effective_occupancy < 70) { opportunities.push('Room for occupancy improvement through better marketing'); } // Calculate risk score const risk_score = Math.min(100, Math.max(0, 50 - (annual_cash_flow / 1000) + risks.length * 10)); return { risk_level: risk_score > 70 ? 'High' : risk_score > 40 ? 'Medium' : 'Low', risk_score: risk_score, key_risks: risks, opportunities: opportunities, stress_scenarios: { occupancy_drop_20pct: { annual_cash_flow: annual_cash_flow - (revenue_analysis.annual_gross_revenue * 0.2), impact: 'Severe' }, rate_drop_15pct: { annual_cash_flow: annual_cash_flow - (revenue_analysis.annual_room_revenue * 0.15), impact: 'Moderate' }, expense_increase_25pct: { annual_cash_flow: annual_cash_flow - (expense_analysis.total_annual_expenses * 0.25), impact: 'Moderate' } } }; } calculateBreakeven(revenue_analysis, expense_analysis, debt_service, rental_assumptions) { const total_fixed_costs = expense_analysis.total_annual_expenses + debt_service; const revenue_per_night = revenue_analysis.annual_gross_revenue / revenue_analysis.occupied_nights_per_year; const breakeven_nights = Math.ceil(total_fixed_costs / revenue_per_night); const breakeven_occupancy = (breakeven_nights / 365) * 100; const current_margin = revenue_analysis.occupied_nights_per_year - breakeven_nights; const margin_days = Math.max(0, current_margin); return { breakeven_nights_per_year: breakeven_nights, breakeven_occupancy_rate: breakeven_occupancy, current_occupancy_rate: rental_assumptions.occupancy_rate, margin_of_safety_nights: margin_days, margin_of_safety_percent: ((rental_assumptions.occupancy_rate - breakeven_occupancy) / rental_assumptions.occupancy_rate) * 100 }; } generateRecommendations(cash_on_cash_return, cap_rate, risk_analysis, traditional_rental, revenue_analysis, property_info) { const recommendations = []; // Investment decision if (cash_on_cash_return > 15 && cap_rate > 8) { recommendations.push({ category: 'Investment Decision', priority: 'high', message: 'Excellent STR opportunity with strong returns' }); } else if (cash_on_cash_return > traditional_rental.cash_on_cash_return + 5) { recommendations.push({ category: 'Investment Decision', priority: 'medium', message: 'STR significantly outperforms traditional rental' }); } else if (cash_on_cash_return < traditional_rental.cash_on_cash_return) { recommendations.push({ category: 'Investment Decision', priority: 'high', message: 'Consider traditional rental - less work, similar returns' }); } // Revenue optimization if (revenue_analysis.effective_occupancy < 65) { recommendations.push({ category: 'Revenue Optimization', priority: 'high', message: 'Focus on marketing and guest experience to improve occupancy' }); } if (revenue_analysis.revenue_per_occupied_night < 150) { recommendations.push({ category: 'Revenue Optimization', priority: 'medium', message: 'Consider premium amenities to justify higher nightly rates' }); } // Risk management if (risk_analysis.risk_level === 'High') { recommendations.push({ category: 'Risk Management', priority: 'high', message: 'High risk investment - ensure adequate cash reserves' }); } // Market specific if (property_info.location_type === 'tourist_destination') { recommendations.push({ category: 'Market Strategy', priority: 'medium', message: 'Diversify marketing across multiple seasons and guest types' }); } // Operational efficiency if (revenue_analysis.bookings_per_year > 100) { recommendations.push({ category: 'Operations', priority: 'high', message: 'Consider professional management - high booking volume' }); } 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