Skip to main content
Glama
klappe-pm

Real Estate MCP Server

by klappe-pm
property-details.ts5.32 kB
import type { Property } from '../types/real-estate.js'; import { zillowService } from '../services/zillow-service.js'; import { DataSourceError, ValidationError, logError, formatUserError } from '../utils/errors.js'; /** * Property Details Tool - Get comprehensive property information * * Retrieves detailed property information including photos, history, * and enhanced features from Zillow API. */ export async function getPropertyDetails(propertyId: string): Promise<Property | null> { if (!propertyId || propertyId.trim().length === 0) { throw new ValidationError('Property ID is required', 'propertyId'); } console.log(`Getting detailed property information for ID: ${propertyId}`); try { // Get basic property details const property = await zillowService.getPropertyDetails(propertyId); if (!property) { console.log(`Property not found: ${propertyId}`); return null; } // Enhance with additional data in parallel const [photos, priceHistory, comparables] = await Promise.allSettled([ zillowService.getPropertyPhotos(propertyId), zillowService.getPriceHistory(propertyId), zillowService.getComparableProperties(propertyId) ]); // Add photos if available if (photos.status === 'fulfilled' && photos.value.length > 0) { property.photos = photos.value; } // Add price history if available if (priceHistory.status === 'fulfilled' && priceHistory.value.length > 0) { // Transform price history to our format property.priceHistory = priceHistory.value.map(entry => ({ date: new Date(entry.date).toISOString(), price: entry.price, event: entry.event || 'price_change' })); } // Log any failed enhancements (but don't fail the whole request) if (photos.status === 'rejected') { logError(photos.reason, 'Property Photos Enhancement'); } if (priceHistory.status === 'rejected') { logError(priceHistory.reason, 'Price History Enhancement'); } if (comparables.status === 'rejected') { logError(comparables.reason, 'Comparables Enhancement'); } console.log(`Retrieved enhanced property details for ${property.address.street || 'property'}`); return property; } catch (error) { logError(error as Error, 'Property Details'); if (error instanceof ValidationError) { throw error; // Re-throw validation errors as-is } if (error instanceof DataSourceError) { throw new Error(formatUserError(error)); } throw new Error('Failed to retrieve property details. Please try again.'); } } /** * Get property comparables (similar properties) */ export async function getPropertyComparables(propertyId: string): Promise<Property[]> { if (!propertyId || propertyId.trim().length === 0) { throw new ValidationError('Property ID is required', 'propertyId'); } console.log(`Getting comparable properties for ID: ${propertyId}`); try { const comparables = await zillowService.getComparableProperties(propertyId); console.log(`Found ${comparables.length} comparable properties`); return comparables; } catch (error) { logError(error as Error, 'Property Comparables'); if (error instanceof ValidationError) { throw error; } // For comparables, we can return empty array on error console.warn('Failed to get comparables, returning empty array'); return []; } } /** * Enhanced property search with details * Combines search with immediate detail retrieval for better user experience */ export async function searchPropertiesWithDetails( location: string, options: { minPrice?: number; maxPrice?: number; minBeds?: number; maxResults?: number; } = {} ): Promise<Property[]> { // Import search function here to avoid circular imports const { searchProperties } = await import('./property-search.js'); try { // First, search for properties const searchQuery = { location, minPrice: options.minPrice, maxPrice: options.maxPrice, minBeds: options.minBeds, page: 1 }; const properties = await searchProperties(searchQuery); if (properties.length === 0) { return []; } // Limit results to prevent too many API calls const maxResults = options.maxResults || 5; const limitedProperties = properties.slice(0, maxResults); // Enhance each property with additional details const enhancedProperties = await Promise.allSettled( limitedProperties.map(async (property) => { if (!property.id) return property; try { const detailed = await getPropertyDetails(property.id); return detailed || property; // Fallback to original if details fail } catch { return property; // Fallback to original on any error } }) ); // Return only fulfilled results return enhancedProperties .filter((result): result is PromiseFulfilledResult<Property> => result.status === 'fulfilled' ) .map(result => result.value); } catch (error) { logError(error as Error, 'Enhanced Property Search'); throw new Error(formatUserError(error as Error)); } }

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/klappe-pm/Real-Estate-MCP'

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