Skip to main content
Glama

Real Estate MCP Server

by klappe-pm
index.ts9.22 kB
#!/usr/bin/env node import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod'; import { searchProperties } from './tools/property-search.js'; import { getPropertyDetails, getPropertyComparables, searchPropertiesWithDetails } from './tools/property-details.js'; import { calculateMortgage, calculateAffordability } from './tools/mortgage-calculator.js'; import type { MortgageInput, SearchQuery } from './types/real-estate.js'; import { formatUserError } from './utils/errors.js'; // Create MCP server const server = new McpServer({ name: 'real-estate-mcp', version: '0.1.0', }); // Register property search tool server.registerTool( 'property.search', { title: 'Property Search', description: 'Search for properties using real Zillow API data with comprehensive filters and location search.', inputSchema: { location: z.string().describe('Location string, e.g., "Los Angeles, CA", "90210", or "123 Main St, Boston, MA"'), minPrice: z.number().optional().describe('Minimum price in USD'), maxPrice: z.number().optional().describe('Maximum price in USD'), minBeds: z.number().optional().describe('Minimum number of bedrooms'), minBaths: z.number().optional().describe('Minimum number of bathrooms'), minSqft: z.number().optional().describe('Minimum square footage'), maxSqft: z.number().optional().describe('Maximum square footage'), propertyType: z.enum(['single_family', 'condo', 'townhouse', 'apartment', 'multi_family', 'land', 'manufactured']).optional().describe('Type of property'), page: z.number().optional().describe('Page number for pagination (default: 1)'), }, }, async (params) => { try { const query = params as SearchQuery; const results = await searchProperties(query); return { content: [ { type: 'text', text: JSON.stringify({ success: true, location: query.location, count: results.length, properties: results, note: results.length > 0 ? 'Real data from Zillow API' : 'No properties found in this area' }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: formatUserError(error as Error), suggestion: 'Try adjusting your search criteria or check if your API keys are configured' }, null, 2), }, ], }; } } ); // Register property details tool server.registerTool( 'property.details', { title: 'Property Details', description: 'Get comprehensive property information including photos, price history, and detailed features using Zillow API.', inputSchema: { propertyId: z.string().describe('Property ID (Zillow ZPID) to get detailed information for'), }, }, async (params) => { try { const { propertyId } = params; const property = await getPropertyDetails(propertyId as string); if (!property) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: 'Property not found', propertyId }, null, 2), }, ], }; } return { content: [ { type: 'text', text: JSON.stringify({ success: true, property, note: 'Detailed property information from Zillow API' }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: formatUserError(error as Error), suggestion: 'Ensure the property ID is valid and your API keys are configured' }, null, 2), }, ], }; } } ); // Register property comparables tool server.registerTool( 'property.comparables', { title: 'Property Comparables', description: 'Get similar properties (comparables/comps) for a given property using Zillow API.', inputSchema: { propertyId: z.string().describe('Property ID (Zillow ZPID) to find comparables for'), }, }, async (params) => { try { const { propertyId } = params; const comparables = await getPropertyComparables(propertyId as string); return { content: [ { type: 'text', text: JSON.stringify({ success: true, count: comparables.length, comparables, note: comparables.length > 0 ? 'Comparable properties from Zillow API' : 'No comparable properties found' }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: formatUserError(error as Error), suggestion: 'Ensure the property ID is valid and your API keys are configured' }, null, 2), }, ], }; } } ); // Register enhanced property search tool server.registerTool( 'property.searchDetailed', { title: 'Enhanced Property Search', description: 'Search for properties and immediately get detailed information including photos and features. Limited to 5 results for performance.', inputSchema: { location: z.string().describe('Location string, e.g., "Los Angeles, CA", "90210", or "123 Main St, Boston, MA"'), minPrice: z.number().optional().describe('Minimum price in USD'), maxPrice: z.number().optional().describe('Maximum price in USD'), minBeds: z.number().optional().describe('Minimum number of bedrooms'), maxResults: z.number().optional().describe('Maximum number of detailed results (default: 5, max: 10)'), }, }, async (params) => { try { const { location, minPrice, maxPrice, minBeds, maxResults } = params; const properties = await searchPropertiesWithDetails(location as string, { minPrice, maxPrice, minBeds, maxResults: Math.min(maxResults || 5, 10) // Cap at 10 to prevent excessive API usage }); return { content: [ { type: 'text', text: JSON.stringify({ success: true, location, count: properties.length, properties, note: 'Enhanced property search with detailed information from Zillow API' }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: JSON.stringify({ success: false, error: formatUserError(error as Error), suggestion: 'Try adjusting your search criteria or check if your API keys are configured' }, null, 2), }, ], }; } } ); // Register mortgage calculator tool server.registerTool( 'mortgage.calculate', { title: 'Mortgage Calculator', description: 'Calculate monthly mortgage payment and breakdown.', inputSchema: { homePrice: z.number(), downPayment: z.number(), annualInterestRate: z.number(), termYears: z.number(), propertyTaxAnnual: z.number().optional(), insuranceAnnual: z.number().optional(), hoaMonthly: z.number().optional(), pmiMonthly: z.number().optional(), }, }, async (params) => { const res = calculateMortgage(params as MortgageInput); return { content: [ { type: 'text', text: JSON.stringify(res, null, 2), }, ], }; } ); // Register affordability calculator tool server.registerTool( 'mortgage.affordability', { title: 'Affordability Calculator', description: 'Estimate maximum home price based on a target monthly payment.', inputSchema: { monthlyPayment: z.number(), downPayment: z.number(), annualInterestRate: z.number(), termYears: z.number().default(30), }, }, async (params) => { const { monthlyPayment, downPayment, annualInterestRate, termYears } = params as any; const max = calculateAffordability( monthlyPayment, downPayment, annualInterestRate, termYears || 30 ); return { content: [ { type: 'text', text: JSON.stringify({ maxHomePrice: max }, null, 2), }, ], }; } ); // Start server over stdio async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('Real Estate MCP server running on stdio'); } main().catch((err) => { console.error('Server failed to start:', err); process.exit(1); });

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