The .gitignore had three competing rules — .env.* (line 70), *.env.* (line 259), and a stale negation !.env.example (line 71) that lost to the later rules. Adding the negation at the end of the file so it wins. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nadlan-MCP — חיפוש נדל"ן ושמאי מכריע
כלי web ו-MCP חינמי וקוד פתוח לחיפוש מידע נדל"ני בישראל: עסקאות נדל"ן עדכניות מ-Govmap והחלטות שמאי מכריע ממשרד המשפטים — בממשק עברי מלא עם תמיכת RTL.
TL;DR: הכנס כתובת, גוש+חלקה או שם של שמאי מכריע — מקבל בו-זמנית עסקאות באזור והחלטות שומה רלוונטיות, כולל הורדת PDF.
תוכן עניינים
- מה הכלי עושה
- שני ממשקים — Web ו-MCP
- תכונות עיקריות
- אופני חיפוש
- ארכיטקטורה
- התקנה והפעלה
- API Endpoints
- פריסה (Deployment)
- פיתוח
- ניהול בעיות 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 מחזיר עסקאות מהפוליגון של הרחוב — אבל פוליגון יכול להכיל מספר רחובות. הפתרון שלנו: מציאת העסקה עם מספר חלקה הקרוב ביותר לחלקה המחופשת בתוך אותו גוש — סביר מאוד שהיא באותו רחוב. כך אנחנו מסמנים נכון מה "אותו רחוב" ומה "סביבה קרובה".
📊 שלוש רמות לשומות שמאי מכריע
כל חיפוש לפי גוש+חלקה מחזיר אוטומטית שלוש רמות:
- החלטות תואמות — בדיוק הגוש+חלקה שחיפשת
- החלטות נוספות באותו גוש — חלקות אחרות באותו גוש
- החלטות בגושים סמוכים — גוש ±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
הרצה לוקלית
# 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
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 של כתובת — מחזיר קואורדינטות + גוש/חלקה אם זוהו.
curl "https://nadlan-mcp.dev.marcus-law.co.il/api/search/address?q=הילדסהיימר%2014%20תל%20אביב"
POST /api/search/deals
חיפוש עסקאות סביב כתובת.
{
"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:
{
"block": "6212",
"plot": "894",
"max_results": 30,
"include_nearby": true,
"nearby_block_radius": 2
}
תגובה:
{
"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
פיתוח
בדיקות
# כל הבדיקות
pytest
# רק unit tests
pytest -m unit
# כיסוי
pytest --cov=nadlan_mcp
# בדיקת איכות מלאה (lint + format + tests)
./check-quality.sh
Linting
ruff format . # פורמט
ruff check . --fix # תיקון אוטומטי
פיתוח Frontend
cd web
npm run dev # Vite dev server (HMR)
npm run typecheck # tsc --noEmit
npm run lint
ניהול בעיות RTL
זיהינו והתגברנו על מספר בעיות RTL בדרך הקשה. אם אתה בונה אפליקציית React בעברית, מומלץ:
- הגדרה כפולה:
<html dir="rtl">וגם<body dir="rtl">— חלק מהספריות בודקות אתdocument.body.dirולא אתdocumentElement. - CSS מפורש:
html, body { direction: rtl; }ב-base layer של Tailwind. - DirectionProvider: עטוף את ה-tree של React ב-
<DirectionProvider dir="rtl">של@radix-ui/react-direction. בלי זה, רכיבי Radix (Tabs, Dialog, Select, Popover) ברירת המחדל שלהם היא LTR. - Tabs wrapper: עטוף את
TabsPrimitive.Rootעם defaultdir="rtl"כדי שגם אם DirectionProvider נמחק בעתיד, Tabs יישאר RTL. - Tables:
<table dir="rtl">מפורש על כל טבלה — מבטיח סדר עמודות נכון בכל הדפדפנים. - Logical classes: השתמש ב-
text-start/text-end(לאtext-left/text-right),ms-*/me-*(לאml-*/mr-*),start-*/end-*. אבל זכור: ב-RTL,text-endמצמיד לשמאל, לא לימין. - בדיקה ויזואלית בדפדפן לפני הצהרה ש-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