Files
nadlan-mcp/README.md
T
chaim ed8892fb2b 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>
2026-04-25 17:21:42 +00:00

387 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nadlan-MCP — חיפוש נדל"ן ושמאי מכריע
כלי web ו-MCP חינמי וקוד פתוח לחיפוש מידע נדל"ני בישראל: עסקאות נדל"ן עדכניות מ-Govmap והחלטות שמאי מכריע ממשרד המשפטים — בממשק עברי מלא עם תמיכת RTL.
> **TL;DR:** הכנס כתובת, גוש+חלקה או שם של שמאי מכריע — מקבל בו-זמנית עסקאות באזור והחלטות שומה רלוונטיות, כולל הורדת PDF.
---
## תוכן עניינים
- [מה הכלי עושה](#מה-הכלי-עושה)
- [שני ממשקים — 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`