Add: Decisive appraiser (שמאי מכריע) search via gov.il public API
Adds a new MCP tool `search_decisive_appraisals` that queries the Ministry of Justice public registry (~30K published decisions) by block (גוש), plot (חלקה), appraiser name, committee, decision/publicity date ranges, or free text — and returns metadata + direct PDF URLs. Implementation notes: - New `nadlan_mcp/govil/` package, parallel to `nadlan_mcp/govmap/`, for gov.il APIs that are not Govmap. Pydantic v2 models match the upstream PascalCase response via aliases. - Upstream sits behind an F5 WAF that rejects standard `requests`; uses `curl_cffi` with Chrome 120 impersonation to traverse it. - Static `x-client-id` header (issued to the gov.il SPA, public, visible in any DevTools session) is required by the gateway — without it every call returns a generic 500. - 14 unit tests cover model parsing, body shape, pagination, and the 500-is-fatal contract (configuration error, not retryable). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+44
-30
@@ -69,8 +69,9 @@ class GovmapConfig:
|
||||
|
||||
# Percentage-based backup filtering (catches extreme outliers in heterogeneous data)
|
||||
analysis_use_percentage_backup: bool = field(
|
||||
default_factory=lambda: os.getenv("ANALYSIS_USE_PERCENTAGE_BACKUP", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("ANALYSIS_USE_PERCENTAGE_BACKUP", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
analysis_percentage_threshold: float = field(
|
||||
default_factory=lambda: float(os.getenv("ANALYSIS_PERCENTAGE_THRESHOLD", "0.4"))
|
||||
@@ -91,8 +92,9 @@ class GovmapConfig:
|
||||
|
||||
# Statistical Robustness (for investment analysis)
|
||||
analysis_use_robust_volatility: bool = field(
|
||||
default_factory=lambda: os.getenv("ANALYSIS_USE_ROBUST_VOLATILITY", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("ANALYSIS_USE_ROBUST_VOLATILITY", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
analysis_use_robust_trends: bool = field(
|
||||
default_factory=lambda: os.getenv("ANALYSIS_USE_ROBUST_TRENDS", "true").lower() == "true"
|
||||
@@ -100,8 +102,9 @@ class GovmapConfig:
|
||||
|
||||
# Reporting
|
||||
analysis_include_unfiltered_stats: bool = field(
|
||||
default_factory=lambda: os.getenv("ANALYSIS_INCLUDE_UNFILTERED_STATS", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("ANALYSIS_INCLUDE_UNFILTERED_STATS", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
|
||||
# Distance Filtering for Deal Relevance
|
||||
@@ -119,48 +122,59 @@ class GovmapConfig:
|
||||
|
||||
# MCP Tool Availability (enable/disable specific tools)
|
||||
tool_autocomplete_address_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_AUTOCOMPLETE_ADDRESS_ENABLED", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_AUTOCOMPLETE_ADDRESS_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_get_deals_by_radius_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_GET_DEALS_BY_RADIUS_ENABLED", "false").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_GET_DEALS_BY_RADIUS_ENABLED", "false").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_get_street_deals_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_GET_STREET_DEALS_ENABLED", "false").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_GET_STREET_DEALS_ENABLED", "false").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_get_neighborhood_deals_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_GET_NEIGHBORHOOD_DEALS_ENABLED", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_GET_NEIGHBORHOOD_DEALS_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_find_recent_deals_for_address_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv(
|
||||
"TOOL_FIND_RECENT_DEALS_FOR_ADDRESS_ENABLED", "true"
|
||||
).lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_FIND_RECENT_DEALS_FOR_ADDRESS_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_analyze_market_trends_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_ANALYZE_MARKET_TRENDS_ENABLED", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_ANALYZE_MARKET_TRENDS_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_compare_addresses_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_COMPARE_ADDRESSES_ENABLED", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_COMPARE_ADDRESSES_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_get_valuation_comparables_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_GET_VALUATION_COMPARABLES_ENABLED", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_GET_VALUATION_COMPARABLES_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_get_deal_statistics_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv("TOOL_GET_DEAL_STATISTICS_ENABLED", "true").lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_GET_DEAL_STATISTICS_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_get_market_activity_metrics_enabled: bool = field(
|
||||
default_factory=lambda: os.getenv(
|
||||
"TOOL_GET_MARKET_ACTIVITY_METRICS_ENABLED", "false"
|
||||
).lower()
|
||||
== "true"
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_GET_MARKET_ACTIVITY_METRICS_ENABLED", "false").lower() == "true"
|
||||
)
|
||||
)
|
||||
tool_search_decisive_appraisals_enabled: bool = field(
|
||||
default_factory=lambda: (
|
||||
os.getenv("TOOL_SEARCH_DECISIVE_APPRAISALS_ENABLED", "true").lower() == "true"
|
||||
)
|
||||
)
|
||||
|
||||
def __post_init__(self):
|
||||
|
||||
Reference in New Issue
Block a user