CRITICAL FIX: get_deals_by_radius returns polygon metadata, not deals
## Root Cause
After Pydantic migration, get_deals_by_radius() was attempting to validate
API responses as Deal objects. However, this endpoint returns POLYGON METADATA
(with fields: dealscount, polygon_id, settlementNameHeb), NOT individual deals.
All responses failed Pydantic validation (missing dealAmount, dealDate),
resulting in empty lists and 0 deals returned from ALL queries.
## Fixes Applied
### 1. client.py - get_deals_by_radius()
- Return type: `List[Deal]` → `List[Dict[str, Any]]`
- Remove Pydantic validation - return raw metadata dicts
- Update docstring to clarify this returns polygon metadata
- Add note to use find_recent_deals_for_address() for actual deals
### 2. client.py - find_recent_deals_for_address()
- Update to handle polygon metadata dicts (not Deal objects)
- Use dict.get('polygon_id') instead of model attribute access
- Rename variable: `nearby_deals` → `nearby_polygons` for clarity
### 3. fastmcp_server.py - get_deals_by_radius() tool
- Update to handle dict responses (not Deal objects)
- Remove strip_bloat_fields() call (not needed for metadata)
- Update docstring with WARNING about polygon metadata
- Change response keys: "deals" → "polygons", "total_deals" → "total_polygons"
### 4. Tests
- test_govmap_client.py: Update to expect dicts, not Deal objects
- test_fastmcp_tools.py: Update 3 tests to mock dict responses
## Impact
- ✅ find_recent_deals_for_address() NOW WORKS (was returning 0 deals)
- ✅ All 174 tests passing
- ✅ E2E API test confirmed working with real data
## API Behavior Documented
get_deals_by_radius endpoint design:
1. Returns polygon/area metadata (not individual deals)
2. Extract polygon_ids from metadata
3. Call get_street_deals(polygon_id) to get actual deals
4. This workflow is automated in find_recent_deals_for_address()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -96,33 +96,37 @@ def autocomplete_address(search_text: str) -> str:
|
||||
|
||||
@mcp.tool()
|
||||
def get_deals_by_radius(latitude: float, longitude: float, radius_meters: int = 500) -> str:
|
||||
"""Get real estate deals within a radius of coordinates.
|
||||
|
||||
"""Get polygon metadata within a radius of coordinates.
|
||||
|
||||
**NOTE**: This returns polygon/area metadata, NOT individual deal transactions!
|
||||
Use find_recent_deals_for_address() to get actual deals.
|
||||
|
||||
Args:
|
||||
latitude: Latitude coordinate
|
||||
longitude: Longitude coordinate
|
||||
longitude: Longitude coordinate
|
||||
radius_meters: Search radius in meters (default: 500)
|
||||
|
||||
|
||||
Returns:
|
||||
JSON string containing recent real estate deals in the area
|
||||
JSON string containing polygon metadata (areas with deals nearby)
|
||||
"""
|
||||
try:
|
||||
# Note: GovmapClient expects (longitude, latitude) tuple
|
||||
deals = client.get_deals_by_radius((longitude, latitude), radius_meters)
|
||||
|
||||
if not deals:
|
||||
return f"No deals found within {radius_meters}m of coordinates ({latitude}, {longitude})"
|
||||
|
||||
# Returns polygon metadata dicts, not Deal objects
|
||||
polygons = client.get_deals_by_radius((longitude, latitude), radius_meters)
|
||||
|
||||
if not polygons:
|
||||
return f"No polygons found within {radius_meters}m of coordinates ({latitude}, {longitude})"
|
||||
|
||||
return json.dumps({
|
||||
"total_deals": len(deals),
|
||||
"total_polygons": len(polygons),
|
||||
"search_radius_meters": radius_meters,
|
||||
"center_coordinates": {"latitude": latitude, "longitude": longitude},
|
||||
"deals": strip_bloat_fields(deals)
|
||||
"polygons": polygons # Return dicts directly, no stripping needed
|
||||
}, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in get_deals_by_radius: {e}")
|
||||
return f"Error fetching deals by radius: {str(e)}"
|
||||
return f"Error fetching polygons by radius: {str(e)}"
|
||||
|
||||
@mcp.tool()
|
||||
def get_street_deals(polygon_id: str, limit: int = 100, deal_type: int = 2) -> str:
|
||||
|
||||
Reference in New Issue
Block a user