docs: rewrite README in Hebrew + update project description

Replace the legacy English MCP-only README with a comprehensive Hebrew
README covering the full Web + MCP product: features, architecture,
3-tier appraisals, smart "same street" inference, RTL hardening guide,
deployment topology, all REST endpoints with curl examples.

Also update pyproject.toml description to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 17:21:42 +00:00
parent 41f68a7319
commit ed8892fb2b
2 changed files with 382 additions and 594 deletions
+381 -593
View File
@@ -1,598 +1,386 @@
# Israel Real Estate MCP
# Nadlan-MCP — חיפוש נדל"ן ושמאי מכריע
A Python-based Mission Control Program (MCP) for interacting with the Israeli government's public real estate data API (Govmap). This project provides both a Python library and an MCP server that allows real estate agents, professionals, and AI agents to query recent property deals, analyze market trends, and retrieve detailed real estate information.
כלי web ו-MCP חינמי וקוד פתוח לחיפוש מידע נדל"ני בישראל: עסקאות נדל"ן עדכניות מ-Govmap והחלטות שמאי מכריע ממשרד המשפטים — בממשק עברי מלא עם תמיכת RTL.
## Description
This project provides a comprehensive Python interface to the Israeli government's Govmap API, enabling users to:
- Search for property addresses using autocomplete
- Find geographical coordinates for addresses
- Retrieve block (Gush) and parcel (Helka) information
- Query recent real estate deals by location
- Get detailed street and neighborhood deal information
- Analyze market trends in specific areas
## Features
- **Address Autocomplete**: Search for addresses using free text and get precise coordinates
- **Geospatial Data**: Retrieve block and parcel information for any coordinate point
- **Deal Discovery**: Find real estate deals within a specified radius of any location
- **Street Analysis**: Get detailed deal information for specific streets
- **Neighborhood Insights**: Analyze deals within entire neighborhoods
- **Time-based Filtering**: Search for deals within specific date ranges
- **Comprehensive Search**: High-level function that combines all features to find deals for any address
- **Error Handling**: Robust error handling for network issues and API failures
- **Logging**: Detailed logging for debugging and monitoring
## Installation
### Prerequisites
- Python 3.7 or higher
- pip package manager
### Setup Instructions
1. **Clone the repository:**
```bash
git clone <repository-url>
cd nadlan-mcp
```
2. **Create a virtual environment:**
```bash
python -m venv venv
```
3. **Activate the virtual environment:**
- On Windows:
```bash
venv\Scripts\activate
```
- On macOS/Linux:
```bash
source venv/bin/activate
```
4. **Install the package:**
```bash
pip install -e .
```
Or for development with all dev dependencies:
```bash
pip install -e .[dev]
```
## Usage
### MCP Server (Recommended for AI Agents)
The project includes an MCP (Model Context Protocol) server that allows AI agents to access Israeli real estate data. The server provides multiple deployment options:
#### 1. FastMCP Server (Recommended)
**NEW: Using FastMCP for better compatibility and reliability**
```bash
python run_fastmcp_server.py
```
This starts the FastMCP server which resolves compatibility issues with the standard MCP library.
#### 2. Interactive Demo Server
For testing and demonstration purposes:
```bash
python simple_mcp_server.py
```
This runs an interactive demo where you can test the tools directly in the terminal.
#### 3. Alternative: Interactive Demo
For testing and demonstrations:
```bash
python simple_mcp_server.py
```
This runs an interactive demo where you can test the tools directly in the terminal.
#### 4. Direct Server Module
You can also run the server directly:
```bash
python -m nadlan_mcp.simple_fastmcp_server
```
#### 5. HTTP Server (For Cloud Deployment)
**NEW: HTTP transport for deploying to Render, Railway, Docker, and other cloud platforms**
For production deployment to cloud platforms, use the HTTP server:
```bash
python run_http_server.py
```
This starts the FastMCP server with HTTP transport, listening on port 8000 by default (configurable via PORT environment variable).
**Using Docker:**
Build and run the container:
```bash
# Build the Docker image
docker build -t nadlan-mcp .
# Run the container
docker run -p 8000:8000 nadlan-mcp
# Or with custom port
docker run -p 8080:8080 -e PORT=8080 nadlan-mcp
```
**Environment Variables:**
- `PORT` - HTTP server port (default: 8000)
- `HOST` - Bind address (default: 0.0.0.0)
- See DEPLOYMENT.md for all Govmap API configuration options
**Endpoints:**
- `http://localhost:8000/mcp` - MCP protocol endpoint
- `http://localhost:8000/health` - Health check endpoint
For detailed deployment instructions to Render, Railway, or other platforms, see [DEPLOYMENT.md](DEPLOYMENT.md).
#### MCP Client Configuration
To connect to the server from MCP clients, use the following configuration:
**For Claude Desktop or other MCP clients (FastMCP - Recommended):**
Add to your MCP client configuration:
```json
{
"servers": {
"nadlan-mcp": {
"command": "python",
"args": ["/path/to/nadlan-mcp/run_fastmcp_server.py"],
"env": {}
}
}
}
```
**For development with stdio transport (FastMCP):**
```python
import asyncio
from mcp.client.stdio import stdio_client
async def main():
async with stdio_client(["python", "run_fastmcp_server.py"]) as client:
# List available tools
result = await client.list_tools()
print("Available tools:", result.tools)
# Call a tool
result = await client.call_tool("find_recent_deals_for_address", {
"address": "סוקולוב 38 חולון",
"years_back": 2
})
print("Results:", result)
asyncio.run(main())
```
#### Available MCP Tools
**FastMCP Server provides these 7 tools:**
- 🏠 `find_recent_deals_for_address` - Main comprehensive analysis tool
- 📊 `get_deals_by_radius` - Find deals within a radius of coordinates
- 🏘️ `get_street_deals` - Get deals for a specific street polygon
- 🏘️ `get_neighborhood_deals` - Get deals for a specific neighborhood polygon
- 🔍 `autocomplete_address` - Address search and validation
- 📈 `analyze_market_trends` - Analyze market trends and price patterns
- 📊 `compare_addresses` - Compare multiple addresses
**All Tools Details:**
##### 🏠 `find_recent_deals_for_address`
**Main comprehensive analysis tool**
- **Description**: Find all relevant real estate deals for a given address
- **Parameters**:
- `address` (required): The address to search for (Hebrew or English)
- `years_back` (optional): Number of years to look back (default: 2)
- **Returns**: List of deals with detailed information
**Example usage:**
```json
{
"address": "בן יהודה 1 תל אביב",
"years_back": 3
}
```
##### 📊 `analyze_market_trends`
**Market trend analysis with price insights**
- **Description**: Analyze price trends and market data for an address
- **Parameters**:
- `address` (required): The address to analyze
- `years_back` (optional): Number of years to analyze (default: 2)
- **Returns**: Market analysis with trends, average prices, and insights
**Example usage:**
```json
{
"address": "דיזנגוף 50 תל אביב",
"years_back": 5
}
```
##### 🏘️ `compare_neighborhoods`
**Compare multiple areas**
- **Description**: Compare real estate data across multiple addresses or neighborhoods
- **Parameters**:
- `addresses` (required): List of addresses to compare
- `years_back` (optional): Number of years to analyze (default: 2)
- **Returns**: Comparative analysis with rankings and insights
**Example usage:**
```json
{
"addresses": ["סוקולוב 38 חולון", "בן יהודה 1 תל אביב", "דיזנגוף 50 תל אביב"],
"years_back": 2
}
```
##### 🔍 `autocomplete_address`
**Address search and validation**
- **Description**: Search for and validate Israeli addresses
- **Parameters**:
- `search_text` (required): The address text to search for
- **Returns**: List of matching addresses with coordinates
**Example usage:**
```json
{
"search_text": "רוטשילד תל אביב"
}
```
#### Server Features
- **Async Operations**: All tools run asynchronously for better performance
- **Error Handling**: Comprehensive error handling with meaningful error messages
- **Logging**: Detailed logging for debugging and monitoring
- **Data Validation**: Input validation and sanitization
- **Hebrew Support**: Full support for Hebrew addresses and text
#### Testing the Server
You can test the server using the interactive demo:
```bash
python simple_mcp_server.py
```
This will start an interactive session where you can:
1. List available tools
2. Call tools with parameters
3. See formatted results
4. Test error handling
#### Server Logs
The server provides detailed logging. To see debug information:
```bash
# Set logging level before running
export PYTHONPATH=/path/to/nadlan-mcp
python -c "import logging; logging.basicConfig(level=logging.DEBUG)" run_mcp_server.py
```
#### Troubleshooting
**Connection Issues:**
- Ensure all dependencies are installed: `pip install -e .`
- Check that Python path is correct in client configuration
- Verify the server starts without errors
**Tool Execution Issues:**
- Check network connectivity for API calls
- Verify address format (Hebrew addresses work best)
- Review server logs for detailed error information
**Performance:**
- Use appropriate `years_back` values (2-5 years recommended)
- Large radius searches may take longer
- Consider caching results for repeated queries
### Python Library Usage
```python
from nadlan_mcp.govmap import GovmapClient
# Initialize the client
client = GovmapClient()
# Search for recent deals for a specific address
address = "רוטשילד 1 תל אביב"
deals = client.find_recent_deals_for_address(address, years_back=2)
print(f"Found {len(deals)} deals for {address}")
for deal in deals[:5]: # Show first 5 deals
print(f"Address: {deal.address_description}")
print(f"Date: {deal.deal_date}")
print(f"Price: ₪{deal.deal_amount:,.0f}")
print("---")
```
## Usage Examples
The `examples/` directory contains practical examples:
- **[basic_search.py](examples/basic_search.py)** - Simple address lookup and recent deals
- **[market_analysis.py](examples/market_analysis.py)** - Comprehensive market trend analysis
- **[investment_analysis.py](examples/investment_analysis.py)** - Compare multiple neighborhoods for investment
- **[valuation.py](examples/valuation.py)** - Property valuation using comparable sales
Run any example:
```bash
python examples/basic_search.py
python examples/market_analysis.py
```
See [examples/README.md](examples/README.md) for detailed usage instructions.
### Advanced Usage Examples
#### 1. Address Autocomplete
```python
from nadlan_mcp import GovmapClient
client = GovmapClient()
# Search for an address
result = client.autocomplete_address("בן יהודה 1 תל אביב")
if result['results']:
best_match = result['results'][0]
print(f"Found: {best_match.get('displayName')}")
print(f"Coordinates: {best_match.get('point')}")
```
#### 2. Get Block and Parcel Information
```python
# Get coordinates from address first
autocomplete_result = client.autocomplete_address("דיזנגוף 50 תל אביב")
point = tuple(autocomplete_result['results'][0]['point'])
# Get block and parcel info
gush_helka = client.get_gush_helka(point)
print(f"Block/Parcel info: {gush_helka}")
```
#### 3. Find Deals by Radius
```python
# Find deals within 100 meters of a point
point = (3870923.95, 3766288.07) # Example coordinates
deals = client.get_deals_by_radius(point, radius=100)
print(f"Found {len(deals)} deals within 100m")
for deal in deals:
print(f"- {deal.get('address')}: {deal.get('price')}")
```
#### 4. Street-specific Deals
```python
# Get detailed street deals for a specific polygon
polygon_id = "52190246"
street_deals = client.get_street_deals(
polygon_id,
limit=10,
start_date="2023-01",
end_date="2024-01"
)
print(f"Found {len(street_deals)} street deals")
```
#### 5. Neighborhood Analysis
```python
# Get neighborhood deals
neighborhood_deals = client.get_neighborhood_deals(
polygon_id="52282030",
limit=20,
start_date="2023-01",
end_date="2024-01"
)
print(f"Found {len(neighborhood_deals)} neighborhood deals")
```
### Running the Example Script
The project includes a main example script that demonstrates basic usage:
```bash
python -m nadlan_mcp.main
```
Or run it directly:
```bash
python nadlan_mcp/main.py
```
## API Reference
### GovmapClient Class
The main class for interacting with the Govmap API.
#### Methods
##### `__init__(base_url: str = "https://www.govmap.gov.il/api/")`
Initialize the client with the base API URL.
##### `autocomplete_address(search_text: str) -> Dict[str, Any]`
Search for addresses using autocomplete functionality.
- **Parameters:**
- `search_text`: The address to search for (Hebrew or English)
- **Returns:** Dictionary with search results and coordinates
- **Raises:** `requests.RequestException`, `ValueError`
##### `get_gush_helka(point: Tuple[float, float]) -> Dict[str, Any]`
Get block (Gush) and parcel (Helka) information for coordinates.
- **Parameters:**
- `point`: Tuple of (longitude, latitude)
- **Returns:** Dictionary with block and parcel data
- **Raises:** `requests.RequestException`, `ValueError`
##### `get_deals_by_radius(point: Tuple[float, float], radius: int = 50) -> List[Dict[str, Any]]`
Find deals within a specified radius of a point.
- **Parameters:**
- `point`: Tuple of (longitude, latitude)
- `radius`: Search radius in meters (default: 50)
- **Returns:** List of deal dictionaries
- **Raises:** `requests.RequestException`
##### `get_street_deals(polygon_id: str, limit: int = 10, start_date: Optional[str] = None, end_date: Optional[str] = None) -> List[Dict[str, Any]]`
Get detailed deals for a specific street.
- **Parameters:**
- `polygon_id`: The polygon ID for the street
- `limit`: Maximum number of deals to return (default: 10)
- `start_date`: Start date in 'YYYY-MM' format
- `end_date`: End date in 'YYYY-MM' format
- **Returns:** List of detailed deal information
- **Raises:** `requests.RequestException`
##### `get_neighborhood_deals(polygon_id: str, limit: int = 10, start_date: Optional[str] = None, end_date: Optional[str] = None) -> List[Dict[str, Any]]`
Get deals within the same neighborhood.
- **Parameters:**
- `polygon_id`: The polygon ID for the area
- `limit`: Maximum number of deals to return (default: 10)
- `start_date`: Start date in 'YYYY-MM' format
- `end_date`: End date in 'YYYY-MM' format
- **Returns:** List of neighborhood deals
- **Raises:** `requests.RequestException`
##### `find_recent_deals_for_address(address: str, years_back: int = 2) -> List[Dict[str, Any]]`
**Main function**: Find all relevant deals for an address (combines all other methods).
- **Parameters:**
- `address`: The address to search for
- `years_back`: How many years back to search (default: 2)
- **Returns:** List of all relevant deals, sorted by date
- **Raises:** `ValueError`, `requests.RequestException`
## Govmap API Endpoints
This project uses the following Govmap API endpoints:
- **Autocomplete**: `POST /search-service/autocomplete`
- **Entities by Point**: `POST /layers-catalog/entitiesByPoint`
- **Deals by Radius**: `GET /real-estate/deals/{point}/{radius}`
- **Street Deals**: `GET /real-estate/street-deals/{polygon_id}`
- **Neighborhood Deals**: `GET /real-estate/neighborhood-deals/{polygon_id}`
### API Base URL
```
https://www.govmap.gov.il/api/
```
## Error Handling
The client includes comprehensive error handling:
- **Network Errors**: Handles connection issues and API timeouts
- **API Errors**: Manages HTTP error responses and invalid data
- **Data Validation**: Validates API responses and handles missing data
- **Logging**: Provides detailed logging for debugging issues
## Logging
The project uses Python's built-in logging module. To enable debug logging:
```python
import logging
logging.basicConfig(level=logging.DEBUG)
```
## Testing
Nadlan-MCP has comprehensive test coverage with 304 tests achieving 84% code coverage.
### Running Tests
```bash
# Run all fast tests (default - excludes API health checks)
pytest tests/ -m "not api_health"
# Result: 303 passed, 1 skipped in ~12s
# Run with coverage report
pytest tests/ -m "not api_health" --cov=nadlan_mcp --cov-report=term-missing
# Run API health checks (weekly monitoring)
pytest -m api_health -v
```
### Test Structure
- **304 tests total** with 84% coverage
- **Fast unit tests** - Mocked/fixture-based (~12s)
- **E2E smoke tests** - Minimal API calls (~5s)
- **Comprehensive E2E** - Full API coverage (~5min, optional)
- **API health checks** - Weekly API monitoring (10 tests, run on-demand)
See `TESTING.md` for detailed testing documentation.
## Dependencies
- **requests**: HTTP library for API calls
- **python-dotenv**: Environment variable management
- **mcp**: Model Context Protocol SDK for AI agent integration
- **pytest**: Testing framework
## License
This project is licensed under the MIT License - see the LICENSE file for details.
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request
## Disclaimer
This tool is for educational and professional use only. Please respect the Govmap API terms of service and rate limits. The authors are not responsible for any misuse of this tool.
## Support
For issues, questions, or contributions, please create an issue in the repository.
> **TL;DR:** הכנס כתובת, גוש+חלקה או שם של שמאי מכריע — מקבל בו-זמנית עסקאות באזור והחלטות שומה רלוונטיות, כולל הורדת PDF.
---
**Note**: This project is not officially affiliated with the Israeli government or Govmap. It is an independent tool created to facilitate access to public real estate data.
## תוכן עניינים
- [מה הכלי עושה](#מה-הכלי-עושה)
- [שני ממשקים — Web ו-MCP](#שני-ממשקים--web-ו-mcp)
- [תכונות עיקריות](#תכונות-עיקריות)
- [אופני חיפוש](#אופני-חיפוש)
- [ארכיטקטורה](#ארכיטקטורה)
- [התקנה והפעלה](#התקנה-והפעלה)
- [API Endpoints](#api-endpoints)
- [פריסה (Deployment)](#פריסה-deployment)
- [פיתוח](#פיתוח)
- [ניהול בעיות RTL](#ניהול-בעיות-rtl)
- [רישוי](#רישוי)
---
## מה הכלי עושה
הכלי מחבר בין שני מקורות מידע ממשלתיים שלא היו זמינים יחד עד היום:
| מקור | מה מספק | תדירות עדכון |
|------|---------|--------------|
| **Govmap** (`www.govmap.gov.il`) | עסקאות נדל"ן רשומות מ-2010 ואילך — מחיר, שטח, חדרים, קומה, גוש/חלקה/תת-חלקה | חודשי |
| **משרד המשפטים** (`pub-justice.openapi.gov.il`) | החלטות שמאי מכריע — שומות הכרעה, ערעורים, היטלי השבחה, פיצויי הפקעה, וכד' | שוטף |
המידע מוצג בטבלה אחת, מסונכרן בין המקורות לפי גוש/חלקה, עם קישורים ישירים ל-PDF של ההחלטות.
---
## שני ממשקים — Web ו-MCP
### 1. ממשק Web (React)
ממשק משתמש מלא לבני אדם:
```
https://nadlan-mcp.dev.marcus-law.co.il
```
טופס חיפוש, שתי טבלאות (עסקאות + שומות), פתיחה והורדה של PDF, RTL מלא.
### 2. ממשק MCP (Model Context Protocol)
שרת MCP ל-LLMs ול-AI agents — מאפשר ל-Claude / ChatGPT / כל סוכן AI לחפש בעצמו מידע נדל"ני. נחשף ב-`/mcp` כ-streamable HTTP. כולל 10 כלים:
- `autocomplete_address` — חיפוש כתובת
- `find_recent_deals_for_address` — עסקאות סביב כתובת
- `analyze_market_trends` — ניתוח מגמות מחירים
- `compare_addresses` — השוואה בין שתי כתובות
- `get_valuation_comparables` — השוואות שמאיות
- `get_deal_statistics` — סטטיסטיקה מצרפית
- `get_market_activity_metrics` — מדדי פעילות שוק
- ועוד.
ראה `nadlan_mcp/fastmcp_server.py`.
---
## תכונות עיקריות
### 🔍 שלושה אופני חיפוש בו-זמנית
חיפוש לפי **כתובת** (`קטלב 5 צור הדסה`), לפי **גוש+חלקה** (`גוש 6212 חלקה 894`) או לפי **שם של שמאי מכריע** (`לוי גלבוע`). הממשק מתאים את עצמו אוטומטית.
### 🏢 זיהוי "אותו רחוב" חכם
כשמחפשים לפי גוש+חלקה, ה-Govmap מחזיר עסקאות מהפוליגון של הרחוב — אבל פוליגון יכול להכיל מספר רחובות. הפתרון שלנו: מציאת העסקה עם מספר חלקה הקרוב ביותר לחלקה המחופשת בתוך אותו גוש — סביר מאוד שהיא באותו רחוב. כך אנחנו מסמנים נכון מה "אותו רחוב" ומה "סביבה קרובה".
### 📊 שלוש רמות לשומות שמאי מכריע
כל חיפוש לפי גוש+חלקה מחזיר אוטומטית שלוש רמות:
1. **החלטות תואמות** — בדיוק הגוש+חלקה שחיפשת
2. **החלטות נוספות באותו גוש** — חלקות אחרות באותו גוש
3. **החלטות בגושים סמוכים** — גוש ±2
דה-דופליקציה מובנית מבטיחה שהחלטה לא תופיע פעמיים.
### 📄 PDF Proxy
החלטות שמאי מכריע מאוחסנות בשרת ממשלתי שדורש header של `x-client-id`. דפדפן רגיל לא יכול להוריד אותן ישירות. הכלי מספק proxy endpoint שמטפל בזה — עם whitelist של hosts מותרים למניעת SSRF.
### 🛡️ עקיפת WAF של F5
ה-API של משרד המשפטים מוגן ב-WAF של F5 שחוסם בקשות "לא דפדפניות". הכלי משתמש ב-`curl_cffi` עם impersonation של Chrome 120 (TLS fingerprint תואם דפדפן אמיתי) כדי לעבור את ה-WAF.
### 🌐 RTL מלא
תמיכה מלאה בעברית — כולל `DirectionProvider` של Radix, `dir="rtl"` מפורש על body/tables/Tabs, ועיצוב Tailwind עם classes לוגיים (`text-start`/`text-end`/`ms-*`/`me-*`).
### ⚡ זיהוי חריגים (Outlier Detection)
ניתוחים סטטיסטיים משתמשים בפילטר IQR + סינון אחוזי + גבולות קשיחים, להסרת עסקאות עם נתונים שגויים (טעויות הקלדה, מכירות חלקיות, מקרים חריגים).
---
## אופני חיפוש
### חיפוש לפי כתובת
```
קטלב 5 צור הדסה
הילדסהיימר 14 תל אביב
ויצמן 10 חיפה
```
מחזיר את העסקאות באזור + השומות התואמות לגוש שזוהה.
### חיפוש לפי גוש + חלקה
מתאים כשאין כתובת מדויקת או כשמחפשים פרצל גולמי:
```
גוש: 6212 חלקה: 894
```
פנימית, נשלח ל-Govmap בפורמט `גוש N חלקה M` (Govmap מזהה את הפורמט הזה ב-autocomplete).
### חיפוש לפי שמאי מכריע
מציג את כל ההחלטות שאותו שמאי הכריע בהן:
```
לוי גלבוע
גלית עוזרי
```
לא מציג עסקאות (אין רלוונטיות אזורית).
---
## ארכיטקטורה
```
┌────────────────────────────────────────────────────────────────┐
│ דפדפן (React 19 + Vite) │
│ ─ SearchBar (3 modes) │
│ ─ DealsTable (proximity inference, gush/חלקה columns) │
│ ─ AppraisalsTable (3 tiers: exact / same block / nearby) │
│ ─ TanStack Query, shadcn/ui, RTL DirectionProvider │
└──────────────────────────────────┬─────────────────────────────┘
│ REST + JSON
┌────────────────────────────────────────────────────────────────┐
│ FastAPI + FastMCP (Python 3.13) │
│ │
│ /api/search/address ─→ Govmap autocomplete │
│ /api/search/deals ─→ Govmap deals (radius+polygon) │
│ /api/search/appraisals ─→ gov.il SearchDecisions (3 tiers) │
│ /api/appraisals/pdf ─→ Streaming PDF proxy w/ x-client-id │
│ /mcp ─→ FastMCP streamable-http (LLMs) │
│ / ─→ Static (React build) │
└────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────┐ ┌────────────────────────────┐
│ www.govmap.gov │ │ pub-justice.openapi.gov.il │
│ (no auth) │ │ (x-client-id header, │
│ │ │ curl_cffi Chrome120 TLS) │
└──────────────────┘ └────────────────────────────┘
```
**שכבות הקוד:**
```
nadlan-mcp/
├── nadlan_mcp/
│ ├── fastmcp_server.py # FastMCP tools (10) + clients
│ ├── web_app.py # FastAPI app + REST endpoints + static
│ ├── config.py # GovmapConfig + env vars
│ ├── govmap/ # Govmap API client (Pydantic v2 models)
│ │ ├── client.py # HTTP, retry, rate limiting
│ │ ├── models.py # Deal, AutocompleteResponse, etc.
│ │ ├── filters.py # Deal filtering
│ │ ├── statistics.py # Statistical analysis + outlier filtering
│ │ ├── market_analysis.py # Trends, comparables
│ │ └── outlier_detection.py
│ └── govil/ # gov.il decisive-appraiser client
│ ├── client.py # curl_cffi w/ Chrome impersonation
│ └── models.py # AppraisalDecision, AppraisalDocument
├── web/ # React 19 + Vite + shadcn/ui frontend
│ ├── src/
│ │ ├── App.tsx
│ │ ├── api/{client,types}.ts
│ │ └── components/
│ │ ├── SearchBar.tsx
│ │ ├── DealsTable.tsx
│ │ ├── AppraisalsTable.tsx
│ │ └── ui/ # shadcn-ui primitives (RTL-patched)
│ └── package.json
├── tests/ # 314 tests, 84% coverage
├── Dockerfile # Multi-stage: node build → python runtime
└── .gitea/workflows/deploy.yaml # CI/CD: build → registry → Coolify
```
---
## התקנה והפעלה
### דרישות
- Python 3.13+
- Node 22+ (לבניית ה-frontend)
- pip / venv
### הרצה לוקלית
```bash
# 1) שכפול
git clone https://gitea.dev.marcus-law.co.il/mcp-servers/nadlan-mcp.git
cd nadlan-mcp
# 2) Python — סביבה וירטואלית
python3 -m venv venv
source venv/bin/activate
pip install -e .
# 3) בניית ה-frontend
cd web
npm install
npm run build
cd ..
# 4) הרצת השרת
PORT=8000 python run_http_server.py
```
פתח ב-`http://127.0.0.1:8000`.
### הרצה עם Docker
```bash
docker build -t nadlan-mcp .
docker run -p 8000:8000 nadlan-mcp
```
### משתני סביבה
| משתנה | ברירת מחדל | תיאור |
|--------|------------|--------|
| `PORT` | `8000` | פורט השרת |
| `GOVMAP_BASE_URL` | `https://www.govmap.gov.il/api/` | בסיס API של Govmap |
| `GOVMAP_REQUESTS_PER_SECOND` | `5.0` | rate-limit ל-Govmap |
| `GOVMAP_MAX_RETRIES` | `3` | retry exponential backoff |
| `GOVMAP_DEFAULT_RADIUS` | `50` | רדיוס ברירת מחדל (מטרים) |
| `ANALYSIS_OUTLIER_METHOD` | `iqr` | שיטת זיהוי חריגים (`iqr`/`percent`/`none`) |
| `ANALYSIS_PRICE_PER_SQM_MIN` | `1000` | גבול תחתון נמוך מדי למחיר/מ"ר |
| `ANALYSIS_PRICE_PER_SQM_MAX` | `100000` | גבול עליון |
ראה רשימה מלאה ב-`nadlan_mcp/config.py`.
---
## API Endpoints
כל ה-endpoints נחשפים תחת `/api/` (גם `/api/docs` לתיעוד OpenAPI/Swagger).
### `GET /api/search/address?q=<query>`
Autocomplete של כתובת — מחזיר קואורדינטות + גוש/חלקה אם זוהו.
```bash
curl "https://nadlan-mcp.dev.marcus-law.co.il/api/search/address?q=הילדסהיימר%2014%20תל%20אביב"
```
### `POST /api/search/deals`
חיפוש עסקאות סביב כתובת.
```json
{
"address": "גוש 6212 חלקה 894",
"years_back": 3,
"radius_meters": 100,
"max_deals": 50,
"deal_type": 2
}
```
תגובה כוללת `search.resolved_address` (הטקסט המפוענח של Govmap), `total`, ו-`deals[]` עם השדות `streetNameHeb`, `houseNum`, `gushNum`, `parcelNum`, `subParcelNum`, `deal_amount`, `asset_area`, `price_per_sqm`, `deal_source` (`same_building` / `street` / `neighborhood`), ועוד.
### `POST /api/search/appraisals`
חיפוש החלטות שמאי מכריע. כשמעבירים `include_nearby: true` עם block, מחזיר 3 buckets:
```json
{
"block": "6212",
"plot": "894",
"max_results": 30,
"include_nearby": true,
"nearby_block_radius": 2
}
```
תגובה:
```json
{
"total_in_db": 13420,
"returned": 5,
"decisions": [...],
"same_block": { "count": 12, "decisions": [...] },
"nearby_blocks": { "count": 8, "decisions": [...] }
}
```
### `GET /api/appraisals/pdf?url=<encoded>`
Proxy ל-PDF של החלטה. רק hosts ב-whitelist (`pub-justice.openapi.gov.il`). הוסף `&download=1` לכפיית הורדה.
### `/mcp`
FastMCP streamable-http endpoint — לחיבור LLMs ו-AI agents.
---
## פריסה (Deployment)
הפריסה ל-`nadlan-mcp.dev.marcus-law.co.il` אוטומטית דרך CI/CD:
```
git push → Gitea Actions → build Docker image
→ push to private registry
→ trigger Coolify webhook
→ pull + redeploy
```
ראה `.gitea/workflows/deploy.yaml`.
**Stack:**
- Coolify (orchestration)
- Traefik 3.6 (reverse proxy + Let's Encrypt)
- Docker registry פרטי
- Python 3.13 slim image
---
## פיתוח
### בדיקות
```bash
# כל הבדיקות
pytest
# רק unit tests
pytest -m unit
# כיסוי
pytest --cov=nadlan_mcp
# בדיקת איכות מלאה (lint + format + tests)
./check-quality.sh
```
### Linting
```bash
ruff format . # פורמט
ruff check . --fix # תיקון אוטומטי
```
### פיתוח Frontend
```bash
cd web
npm run dev # Vite dev server (HMR)
npm run typecheck # tsc --noEmit
npm run lint
```
---
## ניהול בעיות RTL
זיהינו והתגברנו על מספר בעיות RTL בדרך הקשה. אם אתה בונה אפליקציית React בעברית, מומלץ:
1. **הגדרה כפולה:** `<html dir="rtl">` **וגם** `<body dir="rtl">` — חלק מהספריות בודקות את `document.body.dir` ולא את `documentElement`.
2. **CSS מפורש:** `html, body { direction: rtl; }` ב-base layer של Tailwind.
3. **DirectionProvider:** עטוף את ה-tree של React ב-`<DirectionProvider dir="rtl">` של `@radix-ui/react-direction`. בלי זה, רכיבי Radix (Tabs, Dialog, Select, Popover) ברירת המחדל שלהם היא LTR.
4. **Tabs wrapper:** עטוף את `TabsPrimitive.Root` עם default `dir="rtl"` כדי שגם אם DirectionProvider נמחק בעתיד, Tabs יישאר RTL.
5. **Tables:** `<table dir="rtl">` מפורש על כל טבלה — מבטיח סדר עמודות נכון בכל הדפדפנים.
6. **Logical classes:** השתמש ב-`text-start`/`text-end` (לא `text-left`/`text-right`), `ms-*`/`me-*` (לא `ml-*`/`mr-*`), `start-*`/`end-*`. אבל זכור: ב-RTL, **`text-end` מצמיד לשמאל**, לא לימין.
7. **בדיקה ויזואלית בדפדפן** לפני הצהרה ש-task UI הסתיים. build מוצלח לא מספיק.
---
## רישוי
MIT — ראה `LICENSE`.
---
## קישורים
- 🌐 **Web app:** https://nadlan-mcp.dev.marcus-law.co.il
- 📦 **Repo:** https://gitea.dev.marcus-law.co.il/mcp-servers/nadlan-mcp
- 📚 **API docs (Swagger):** https://nadlan-mcp.dev.marcus-law.co.il/api/docs
- 🛠 **MCP endpoint:** https://nadlan-mcp.dev.marcus-law.co.il/mcp
- 📖 **תיעוד אדריכלי:** `ARCHITECTURE.md`
- 🚀 **תיעוד פריסה:** `DEPLOYMENT.md`
- 📝 **שינויים:** `CHANGELOG.md`
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "nadlan-mcp"
version = "2.0.0"
description = "Israeli Real Estate MCP Server"
description = "חיפוש עסקאות נדל\"ן (Govmap) והחלטות שמאי מכריע (משרד המשפטים) — שרת MCP + ממשק Web עברי עם תמיכת RTL"
readme = "README.md"
requires-python = ">=3.7"
license = {text = "MIT"}