""" MCP tool for executing PromQL instant queries. Real-time Prometheus metric evaluations at a single point in time. Returns JSON in Prometheus API format: {"status": "success", "data": {"resultType": "vector", "result": [...], "warnings": []}}. """ import json from typing import Any from pydantic import ValidationError as PydanticValidationError from src.models.query_instant import InstantQueryRequest from src.services.auth import get_valid_server_auth from src.services.prometheus import get_prometheus_client_for_cluster from src.tools.constants import INSTANT_QUERY_TIMEOUT from src.tools.query_range import mcp from src.utils.errors import ( AuthorizationError, AuthServiceError, NetworkError, PrometheusAPIError, PrometheusTimeoutError, ValidationError, ) from src.utils.logging_utils import get_logger from src.utils.redaction import redact_labels from src.utils.tool_response import format_tool_error, tool_text_response logger = get_logger("tool.query_instant") @mcp.tool() async def query_instant( query: str, cluster_id: str, env: str, deploy_type: str, time: str | None = None, ) -> list[dict[str, Any]]: """ Execute a PromQL instant query at a single point in time. WORKFLOW: `list_metrics` -> `list_metric_labels` -> `list_metric_label_values` -> `query_instant` for metric data. Returns Prometheus /api/v1/query JSON data. """ try: logger.info( "tool_call_start name=query_instant cluster_id=%s env=%s deploy_type=%s", cluster_id, env, deploy_type, ) await get_valid_server_auth() try: request = InstantQueryRequest.model_validate( { "query": query, "cluster_id": str(cluster_id).strip(), "env": env.strip(), "deploy_type": deploy_type.strip(), "time": time, } ) except (ValueError, PydanticValidationError) as e: raise ValidationError(f"Invalid instant query parameters: {str(e)}") from e client = await get_prometheus_client_for_cluster( cluster_id=request.cluster_id, env=request.env, deploy_type=request.deploy_type, timeout=INSTANT_QUERY_TIMEOUT, ) response = await client.query_instant( query=request.query, time=request.time, timeout=INSTANT_QUERY_TIMEOUT, ) # Redact sensitive labels in each result; keep Prometheus response structure result_data = response.get("data", {}).get("result", []) for item in result_data: metric = item.get("metric", {}) if metric: item["metric"] = redact_labels(metric) logger.info( "tool_call_success name=query_instant cluster_id=%s series_count=%s", request.cluster_id, len(result_data), ) return tool_text_response(json.dumps(response, ensure_ascii=False)) except ( AuthServiceError, AuthorizationError, ValidationError, NetworkError, PrometheusTimeoutError, PrometheusAPIError, ) as e: logger.warning("tool_call_error name=query_instant type=%s", e.__class__.__name__) return tool_text_response(format_tool_error(e)) except Exception as e: logger.exception("tool_call_unexpected_error name=query_instant") return tool_text_response(format_tool_error(e))