Skip to main content
Glama
sigaihealth

RealVest Real Estate MCP Server

loan-comparison.js20.4 kB
export class LoanComparisonTool { constructor() { this.name = 'Loan Comparison Tool'; this.description = 'Compare multiple mortgage loan scenarios side by side'; } getSchema() { return { type: 'object', properties: { home_price: { type: 'number', description: 'Purchase price of the home', minimum: 0 }, loans: { type: 'array', description: 'Array of loan scenarios to compare (2-4 loans)', minItems: 2, maxItems: 4, items: { type: 'object', properties: { loan_name: { type: 'string', description: 'Name/label for this loan option' }, down_payment_percent: { type: 'number', description: 'Down payment percentage', minimum: 0, maximum: 100 }, interest_rate: { type: 'number', description: 'Annual interest rate (%)', minimum: 0, maximum: 20 }, loan_term_years: { type: 'number', description: 'Loan term in years', enum: [10, 15, 20, 25, 30] }, loan_type: { type: 'string', description: 'Type of loan', enum: ['conventional', 'fha', 'va', 'usda', 'jumbo', 'arm'], default: 'conventional' }, points: { type: 'number', description: 'Discount points to buy down rate', minimum: 0, maximum: 4, default: 0 }, pmi_rate: { type: 'number', description: 'PMI rate (% of loan amount annually)', minimum: 0, maximum: 2, default: 0 }, arm_details: { type: 'object', description: 'ARM-specific details (if loan_type is ARM)', properties: { fixed_period_years: { type: 'number', description: 'Initial fixed rate period', enum: [3, 5, 7, 10] }, adjustment_cap: { type: 'number', description: 'Max rate adjustment per period (%)', default: 2 }, lifetime_cap: { type: 'number', description: 'Max lifetime rate increase (%)', default: 5 } } } }, required: ['loan_name', 'down_payment_percent', 'interest_rate', 'loan_term_years'] } }, property_tax_annual: { type: 'number', description: 'Annual property tax amount', minimum: 0, default: 0 }, home_insurance_annual: { type: 'number', description: 'Annual homeowners insurance', minimum: 0, default: 0 }, hoa_monthly: { type: 'number', description: 'Monthly HOA fees', minimum: 0, default: 0 }, comparison_period_years: { type: 'number', description: 'Years to compare total costs', minimum: 1, maximum: 30, default: 5 } }, required: ['home_price', 'loans'] }; } calculate(params) { const { home_price, loans, property_tax_annual = 0, home_insurance_annual = 0, hoa_monthly = 0, comparison_period_years = 5 } = params; // Calculate details for each loan const loanDetails = loans.map(loan => this.calculateLoanDetails( home_price, loan, property_tax_annual, home_insurance_annual, hoa_monthly, comparison_period_years )); // Find best options const bestMonthlyPayment = this.findBestByMetric(loanDetails, 'total_monthly_payment', 'lowest'); const bestTotalInterest = this.findBestByMetric(loanDetails, 'total_interest_paid', 'lowest'); const bestUpfrontCost = this.findBestByMetric(loanDetails, 'total_upfront_costs', 'lowest'); const bestOverallCost = this.findBestByMetric(loanDetails, 'total_cost_over_period', 'lowest'); // Create comparison summary const summary = this.createComparisonSummary(loanDetails, comparison_period_years); // Generate side-by-side comparison const sideBySide = this.createSideBySideComparison(loanDetails); // Calculate break-even analysis for points const pointsAnalysis = this.analyzePointsBreakEven(loanDetails); // ARM risk analysis if applicable const armAnalysis = this.analyzeARMRisks(loanDetails, home_price); return { loan_details: loanDetails, comparison_summary: summary, best_options: { lowest_monthly_payment: bestMonthlyPayment, lowest_total_interest: bestTotalInterest, lowest_upfront_cost: bestUpfrontCost, lowest_overall_cost: bestOverallCost }, side_by_side: sideBySide, points_analysis: pointsAnalysis, arm_risk_analysis: armAnalysis, recommendations: this.generateRecommendations( loanDetails, bestMonthlyPayment, bestOverallCost, comparison_period_years ) }; } calculateLoanDetails(homePrice, loan, propertyTaxAnnual, homeInsuranceAnnual, hoaMonthly, comparisonYears) { const { loan_name, down_payment_percent, interest_rate, loan_term_years, loan_type = 'conventional', points = 0, pmi_rate = 0, arm_details } = loan; // Basic calculations const down_payment = homePrice * (down_payment_percent / 100); const loan_amount = homePrice - down_payment; const monthly_rate = interest_rate / 100 / 12; const num_payments = loan_term_years * 12; const comparison_months = comparisonYears * 12; // Calculate monthly principal & interest const monthly_pi = this.calculateMonthlyPayment(loan_amount, monthly_rate, num_payments); // Calculate PMI if applicable let monthly_pmi = 0; let pmi_months = 0; if (down_payment_percent < 20 && loan_type !== 'va') { const actualPmiRate = pmi_rate || this.getDefaultPMIRate(down_payment_percent, loan_type); monthly_pmi = (loan_amount * actualPmiRate / 100) / 12; // PMI typically drops off at 78% LTV pmi_months = this.calculateMonthsUntilPMIRemoval( loan_amount, homePrice, monthly_pi, monthly_rate ); } // Other monthly costs const monthly_property_tax = propertyTaxAnnual / 12; const monthly_insurance = homeInsuranceAnnual / 12; const total_monthly_payment = monthly_pi + monthly_pmi + monthly_property_tax + monthly_insurance + hoaMonthly; // Upfront costs const points_cost = loan_amount * (points / 100); const estimated_closing_costs = this.estimateClosingCosts(loan_amount, loan_type); const total_upfront_costs = down_payment + points_cost + estimated_closing_costs; // Calculate interest over comparison period const amortization = this.calculateAmortization( loan_amount, monthly_rate, num_payments, comparison_months ); // Total PMI paid over comparison period const pmi_paid_comparison = monthly_pmi * Math.min(pmi_months, comparison_months); // Total cost over comparison period const total_cost_over_period = total_upfront_costs + (monthly_pi * comparison_months) + pmi_paid_comparison + (monthly_property_tax * comparison_months) + (monthly_insurance * comparison_months) + (hoaMonthly * comparison_months); return { loan_name: loan_name, loan_type: loan_type, loan_amount: parseFloat(loan_amount.toFixed(2)), down_payment: parseFloat(down_payment.toFixed(2)), down_payment_percent: down_payment_percent, interest_rate: interest_rate, loan_term_years: loan_term_years, points: points, monthly_payment_breakdown: { principal_interest: parseFloat(monthly_pi.toFixed(2)), pmi: parseFloat(monthly_pmi.toFixed(2)), property_tax: parseFloat(monthly_property_tax.toFixed(2)), home_insurance: parseFloat(monthly_insurance.toFixed(2)), hoa: hoaMonthly, total: parseFloat(total_monthly_payment.toFixed(2)) }, total_monthly_payment: parseFloat(total_monthly_payment.toFixed(2)), upfront_costs: { down_payment: parseFloat(down_payment.toFixed(2)), points_cost: parseFloat(points_cost.toFixed(2)), estimated_closing: parseFloat(estimated_closing_costs.toFixed(2)), total: parseFloat(total_upfront_costs.toFixed(2)) }, total_upfront_costs: parseFloat(total_upfront_costs.toFixed(2)), comparison_period_analysis: { months: comparison_months, principal_paid: parseFloat(amortization.principal_paid.toFixed(2)), interest_paid: parseFloat(amortization.interest_paid.toFixed(2)), pmi_paid: parseFloat(pmi_paid_comparison.toFixed(2)), remaining_balance: parseFloat(amortization.remaining_balance.toFixed(2)), equity_built: parseFloat((down_payment + amortization.principal_paid).toFixed(2)) }, total_interest_paid: parseFloat(amortization.interest_paid.toFixed(2)), total_cost_over_period: parseFloat(total_cost_over_period.toFixed(2)), lifetime_costs: { total_interest: parseFloat(((monthly_pi * num_payments) - loan_amount).toFixed(2)), total_pmi: parseFloat((monthly_pmi * pmi_months).toFixed(2)), total_paid: parseFloat(((monthly_pi * num_payments) + (monthly_pmi * pmi_months) + total_upfront_costs).toFixed(2)) }, pmi_details: { has_pmi: monthly_pmi > 0, monthly_pmi: parseFloat(monthly_pmi.toFixed(2)), months_until_removal: pmi_months, total_pmi_paid: parseFloat((monthly_pmi * pmi_months).toFixed(2)) }, arm_details: arm_details }; } calculateMonthlyPayment(principal, monthlyRate, numPayments) { if (monthlyRate === 0) { return principal / numPayments; } return principal * (monthlyRate * Math.pow(1 + monthlyRate, numPayments)) / (Math.pow(1 + monthlyRate, numPayments) - 1); } getDefaultPMIRate(downPaymentPercent, loanType) { if (loanType === 'fha') { return 0.85; // FHA MIP } // Conventional PMI rates based on down payment if (downPaymentPercent >= 15) return 0.25; if (downPaymentPercent >= 10) return 0.45; if (downPaymentPercent >= 5) return 0.75; return 1.0; } calculateMonthsUntilPMIRemoval(loanAmount, homePrice, monthlyPayment, monthlyRate) { const targetBalance = homePrice * 0.78; // 78% LTV let balance = loanAmount; let months = 0; while (balance > targetBalance && months < 360) { const interestPayment = balance * monthlyRate; const principalPayment = monthlyPayment - interestPayment; balance -= principalPayment; months++; } return months; } estimateClosingCosts(loanAmount, loanType) { // Rough estimates for closing costs const rates = { conventional: 0.025, fha: 0.03, va: 0.02, usda: 0.025, jumbo: 0.02, arm: 0.025 }; return loanAmount * (rates[loanType] || 0.025); } calculateAmortization(principal, monthlyRate, totalPayments, periodMonths) { let balance = principal; let totalInterest = 0; let totalPrincipal = 0; const monthlyPayment = this.calculateMonthlyPayment(principal, monthlyRate, totalPayments); for (let month = 1; month <= periodMonths && month <= totalPayments; month++) { const interestPayment = balance * monthlyRate; const principalPayment = monthlyPayment - interestPayment; totalInterest += interestPayment; totalPrincipal += principalPayment; balance -= principalPayment; } return { principal_paid: totalPrincipal, interest_paid: totalInterest, remaining_balance: Math.max(0, balance) }; } findBestByMetric(loanDetails, metric, direction = 'lowest') { const getValue = (loan) => { const keys = metric.split('.'); return keys.reduce((obj, key) => obj[key], loan); }; const sorted = [...loanDetails].sort((a, b) => { const valA = getValue(a); const valB = getValue(b); return direction === 'lowest' ? valA - valB : valB - valA; }); const best = sorted[0]; const savings = sorted.slice(1).map(loan => ({ loan_name: loan.loan_name, difference: getValue(loan) - getValue(best) })); return { loan_name: best.loan_name, value: getValue(best), savings_vs_others: savings }; } createComparisonSummary(loanDetails, comparisonYears) { const metrics = { monthly_payments: loanDetails.map(l => ({ loan: l.loan_name, amount: l.total_monthly_payment })), upfront_costs: loanDetails.map(l => ({ loan: l.loan_name, amount: l.total_upfront_costs })), interest_paid: loanDetails.map(l => ({ loan: l.loan_name, amount: l.total_interest_paid, period: `${comparisonYears} years` })), total_cost: loanDetails.map(l => ({ loan: l.loan_name, amount: l.total_cost_over_period, period: `${comparisonYears} years` })) }; return metrics; } createSideBySideComparison(loanDetails) { const categories = [ { label: 'Loan Amount', key: 'loan_amount' }, { label: 'Down Payment', key: 'down_payment' }, { label: 'Interest Rate', key: 'interest_rate', suffix: '%' }, { label: 'Term', key: 'loan_term_years', suffix: ' years' }, { label: 'Monthly P&I', key: 'monthly_payment_breakdown.principal_interest' }, { label: 'Monthly PMI', key: 'monthly_payment_breakdown.pmi' }, { label: 'Total Monthly', key: 'total_monthly_payment' }, { label: 'Upfront Costs', key: 'total_upfront_costs' }, { label: 'Points Cost', key: 'upfront_costs.points_cost' }, { label: '5-Year Interest', key: 'total_interest_paid' }, { label: '5-Year Total Cost', key: 'total_cost_over_period' }, { label: 'Lifetime Interest', key: 'lifetime_costs.total_interest' } ]; const comparison = categories.map(cat => { const row = { category: cat.label }; loanDetails.forEach(loan => { const value = cat.key.split('.').reduce((obj, key) => obj[key], loan); row[loan.loan_name] = typeof value === 'number' ? `$${value.toLocaleString()}${cat.suffix || ''}` : value + (cat.suffix || ''); }); return row; }); return comparison; } analyzePointsBreakEven(loanDetails) { const pointsAnalysis = []; loanDetails.forEach(loan => { if (loan.points > 0) { // Find comparison loan without points const baseComparison = loanDetails.find(l => l.loan_type === loan.loan_type && l.down_payment_percent === loan.down_payment_percent && l.points === 0 ); if (baseComparison) { const monthlySavings = baseComparison.monthly_payment_breakdown.principal_interest - loan.monthly_payment_breakdown.principal_interest; const breakEvenMonths = loan.upfront_costs.points_cost / monthlySavings; pointsAnalysis.push({ loan_name: loan.loan_name, points: loan.points, points_cost: loan.upfront_costs.points_cost, monthly_savings: parseFloat(monthlySavings.toFixed(2)), break_even_months: Math.ceil(breakEvenMonths), break_even_years: parseFloat((breakEvenMonths / 12).toFixed(1)), worth_it: breakEvenMonths < (loan.loan_term_years * 12 * 0.7) // Worth it if break even before 70% of term }); } } }); return pointsAnalysis; } analyzeARMRisks(loanDetails, homePrice) { const armLoans = loanDetails.filter(l => l.loan_type === 'arm'); if (armLoans.length === 0) return null; return armLoans.map(loan => { const maxRate = loan.interest_rate + (loan.arm_details?.lifetime_cap || 5); const maxMonthlyRate = maxRate / 100 / 12; const maxPayment = this.calculateMonthlyPayment( loan.loan_amount, maxMonthlyRate, loan.loan_term_years * 12 ); return { loan_name: loan.loan_name, initial_rate: loan.interest_rate, max_possible_rate: maxRate, current_payment: loan.monthly_payment_breakdown.principal_interest, max_possible_payment: parseFloat(maxPayment.toFixed(2)), payment_increase: parseFloat((maxPayment - loan.monthly_payment_breakdown.principal_interest).toFixed(2)), payment_increase_percent: parseFloat( ((maxPayment - loan.monthly_payment_breakdown.principal_interest) / loan.monthly_payment_breakdown.principal_interest * 100).toFixed(2) ), fixed_period: loan.arm_details?.fixed_period_years || 5, risk_assessment: maxPayment > loan.monthly_payment_breakdown.principal_interest * 1.25 ? "High Risk" : "Moderate Risk" }; }); } generateRecommendations(loanDetails, bestMonthly, bestOverall, comparisonYears) { const recommendations = []; // Best overall value if (bestOverall.loan_name === bestMonthly.loan_name) { recommendations.push({ type: "Best Choice", message: `${bestOverall.loan_name} offers both lowest monthly payment and lowest total cost`, action: "This is likely your best option unless you have specific constraints" }); } else { recommendations.push({ type: "Trade-off", message: `${bestMonthly.loan_name} has lowest monthly payment, but ${bestOverall.loan_name} saves more over ${comparisonYears} years`, action: "Choose based on your monthly budget vs long-term savings priority" }); } // PMI considerations const loansWithPMI = loanDetails.filter(l => l.pmi_details.has_pmi); if (loansWithPMI.length > 0) { const loansWithoutPMI = loanDetails.filter(l => !l.pmi_details.has_pmi); if (loansWithoutPMI.length > 0) { const pmiSavings = Math.min(...loansWithPMI.map(l => l.pmi_details.total_pmi_paid)); recommendations.push({ type: "PMI Avoidance", message: `20% down payment options save $${pmiSavings.toLocaleString()} in PMI`, action: "Consider if you can afford the higher down payment" }); } } // Points analysis const loansWithPoints = loanDetails.filter(l => l.points > 0); if (loansWithPoints.length > 0) { recommendations.push({ type: "Points Strategy", message: "Some options include discount points", action: "Points are worthwhile if you plan to keep the loan long-term" }); } // ARM warnings const armLoans = loanDetails.filter(l => l.loan_type === 'arm'); if (armLoans.length > 0) { recommendations.push({ type: "ARM Caution", message: "ARM loans carry interest rate risk after the fixed period", action: "Only choose ARM if you plan to sell/refinance before rate adjustments" }); } // Short vs long term const shortTermLoans = loanDetails.filter(l => l.loan_term_years <= 15); const longTermLoans = loanDetails.filter(l => l.loan_term_years >= 30); if (shortTermLoans.length > 0 && longTermLoans.length > 0) { const interestSavings = Math.min(...longTermLoans.map(l => l.lifetime_costs.total_interest)) - Math.min(...shortTermLoans.map(l => l.lifetime_costs.total_interest)); recommendations.push({ type: "Term Length", message: `15-year loans save ~$${interestSavings.toLocaleString()} in lifetime interest`, action: "Choose shorter term if you can afford the higher payment" }); } 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