add health check tool

This commit is contained in:
saidsurucu
2025-07-13 22:31:34 +03:00
parent 35f3b739d4
commit f492109eb7
3 changed files with 161 additions and 6 deletions
+144 -2
View File
@@ -1003,7 +1003,7 @@ async def search_yargitay_detailed(
logger.info(f"Tool 'search_yargitay_detailed' called: {search_query.model_dump_json(exclude_none=True, indent=2)}")
try:
api_response = await yargitay_client_instance.search_detailed_decisions(search_query)
if api_response.data:
if api_response and api_response.data and api_response.data.data:
# Convert to clean decision entries without arananKelime field
clean_decisions = [
CleanYargitayDecisionEntry(
@@ -1018,7 +1018,7 @@ async def search_yargitay_detailed(
]
return CompactYargitaySearchResult(
decisions=clean_decisions,
total_records=api_response.data.recordsTotal,
total_records=api_response.data.recordsTotal if api_response.data else 0,
requested_page=search_query.pageNumber,
page_size=search_query.pageSize)
logger.warning("API response for Yargitay search did not contain expected data structure.")
@@ -2321,6 +2321,148 @@ def perform_cleanup():
atexit.register(perform_cleanup)
# --- Health Check Tools ---
@app.tool(
description="Check if Turkish government legal database servers are operational",
annotations={
"readOnlyHint": True,
"idempotentHint": True
}
)
async def check_government_servers_health() -> Dict[str, Any]:
"""Check health status of Turkish government legal database servers."""
logger.info("Health check tool called for government servers")
health_results = {}
# Check Yargıtay server
try:
yargitay_payload = {
"data": {
"aranan": "karar",
"arananKelime": "karar",
"pageSize": 10,
"pageNumber": 1
}
}
async with httpx.AsyncClient(
headers={
"Accept": "*/*",
"Accept-Language": "tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7",
"Connection": "keep-alive",
"Content-Type": "application/json; charset=UTF-8",
"Origin": "https://karararama.yargitay.gov.tr",
"Referer": "https://karararama.yargitay.gov.tr/",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
},
timeout=30.0,
verify=False
) as client:
response = await client.post(
"https://karararama.yargitay.gov.tr/aramalist",
json=yargitay_payload
)
if response.status_code == 200:
response_data = response.json()
records_total = response_data.get("data", {}).get("recordsTotal", 0)
if records_total > 0:
health_results["yargitay"] = {
"status": "healthy",
"records_total": records_total,
"response_time_ms": response.elapsed.total_seconds() * 1000
}
else:
health_results["yargitay"] = {
"status": "unhealthy",
"reason": "recordsTotal is 0 or missing",
"response_time_ms": response.elapsed.total_seconds() * 1000
}
else:
health_results["yargitay"] = {
"status": "unhealthy",
"reason": f"HTTP {response.status_code}",
"response_time_ms": response.elapsed.total_seconds() * 1000
}
except Exception as e:
health_results["yargitay"] = {
"status": "unhealthy",
"reason": f"Connection error: {str(e)}"
}
# Check Bedesten API server
try:
bedesten_payload = {
"phrase": "karar",
"itemTypeList": ["YARGITAYKARARI"],
"pageSize": 5,
"page": 1
}
async with httpx.AsyncClient(
headers={
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0 Health Check"
},
timeout=30.0,
verify=False
) as client:
response = await client.post(
"https://bedesten.adalet.gov.tr/api/search",
json=bedesten_payload
)
if response.status_code == 200:
response_data = response.json()
total_found = response_data.get("totalFound", 0)
if total_found > 0:
health_results["bedesten"] = {
"status": "healthy",
"total_found": total_found,
"response_time_ms": response.elapsed.total_seconds() * 1000
}
else:
health_results["bedesten"] = {
"status": "unhealthy",
"reason": "totalFound is 0 or missing",
"response_time_ms": response.elapsed.total_seconds() * 1000
}
else:
health_results["bedesten"] = {
"status": "unhealthy",
"reason": f"HTTP {response.status_code}",
"response_time_ms": response.elapsed.total_seconds() * 1000
}
except Exception as e:
health_results["bedesten"] = {
"status": "unhealthy",
"reason": f"Connection error: {str(e)}"
}
# Overall health assessment
healthy_servers = sum(1 for server in health_results.values() if server["status"] == "healthy")
total_servers = len(health_results)
overall_status = "healthy" if healthy_servers == total_servers else "degraded" if healthy_servers > 0 else "unhealthy"
return {
"overall_status": overall_status,
"healthy_servers": healthy_servers,
"total_servers": total_servers,
"servers": health_results,
"check_timestamp": f"{__import__('datetime').datetime.now().isoformat()}"
}
# --- MCP Tools for KVKK ---
@app.tool(
description="Search KVKK decisions using Brave Search API for data protection authority decisions. Before using, read docs://tools/kvkk",
+13
View File
@@ -65,6 +65,19 @@ class YargitayOfficialApiClient:
response.raise_for_status() # Raise an exception for HTTP 4xx or 5xx status codes
response_json_data = response.json()
logger.debug(f"YargitayOfficialApiClient: Raw API response: {response_json_data}")
# Handle None or empty data response from API
if response_json_data is None:
logger.warning("YargitayOfficialApiClient: API returned None response")
response_json_data = {"data": {"data": [], "recordsTotal": 0, "recordsFiltered": 0}}
elif not isinstance(response_json_data, dict):
logger.warning(f"YargitayOfficialApiClient: API returned unexpected response type: {type(response_json_data)}")
response_json_data = {"data": {"data": [], "recordsTotal": 0, "recordsFiltered": 0}}
elif response_json_data.get("data") is None:
logger.warning("YargitayOfficialApiClient: API response data field is None")
response_json_data["data"] = {"data": [], "recordsTotal": 0, "recordsFiltered": 0}
# Validate and parse the response using Pydantic models
api_response = YargitayApiSearchResponse(**response_json_data)
+4 -4
View File
@@ -74,14 +74,14 @@ class YargitayApiDecisionEntry(BaseModel):
class YargitayApiResponseInnerData(BaseModel):
"""Model for the inner 'data' object in the Yargitay API search response."""
data: List[YargitayApiDecisionEntry]
data: List[YargitayApiDecisionEntry] = Field(default_factory=list)
# draw: Optional[int] = None # Typically used by DataTables, not essential for MCP
recordsTotal: int # Total number of records matching the query
recordsFiltered: int # Total number of records after filtering (usually same as recordsTotal)
recordsTotal: int = Field(default=0) # Total number of records matching the query
recordsFiltered: int = Field(default=0) # Total number of records after filtering (usually same as recordsTotal)
class YargitayApiSearchResponse(BaseModel):
"""Model for the complete search response from the Yargitay API."""
data: YargitayApiResponseInnerData
data: Optional[YargitayApiResponseInnerData] = Field(default_factory=lambda: YargitayApiResponseInnerData())
# metadata: Optional[Dict[str, Any]] = None # Optional metadata from API
class YargitayDocumentMarkdown(BaseModel):