""" MCP tool for executing Loki range queries. This tool allows authorized AI agents and developers to query historical log data from Loki over a specified time range. Returns JSON in Loki API format: {"status": "success", "data": {"resultType": "streams", "result": [...], "warnings": []}}. """ import json import logging from typing import Any from pydantic import ValidationError as PydanticValidationError from src.models.loki_queries import LokiQueryRangeRequest from src.services.auth import get_valid_server_auth from src.services.loki_resolve import add_env_to_query, get_loki_client_for_cluster from src.tools.query_range import mcp from src.utils.errors import ( AuthorizationError, AuthServiceError, LokiAPIError, LokiTimeoutError, NetworkError, ValidationError, ) from src.utils.tool_response import format_tool_error, tool_text_response logger = logging.getLogger(__name__) @mcp.tool() async def query_loki_range( query: str, start: str, end: str, cluster_id: str, env: str, deploy_type: str, limit: int = 100, direction: str = "backward", step: str | None = None, ) -> list[dict[str, Any]]: """ Execute a Loki range query to retrieve historical log data. Returns JSON in the same format as Loki /loki/api/v1/query_range: {"status": "success", "data": {"resultType": "streams", "result": [...], "warnings": []}}. Args: query: LogQL query string (e.g., '{app="mysql", level="error"}') start: Start timestamp in RFC3339 format (e.g., '2024-01-01T00:00:00Z') end: End timestamp in RFC3339 format (e.g., '2024-01-01T23:59:59Z') cluster_id: Cluster identifier. env: Environment name (e.g. prod, staging, dev). Will be added as label filter. deploy_type: Deploy type (dedicated, premium, resource_pool, starter, essential). limit: Maximum number of log entries to return (default: 100, max: 10000) direction: Query direction - "forward" or "backward" (default: "backward") step: Optional step duration for quantization (e.g., '15s', '1m') Returns: List containing a single dict with 'type': 'text' and 'text': Loki-format JSON Raises: Various errors for authorization, validation, network, and timeout issues Examples: # Query MySQL error logs query='{app="mysql", level="error"}' # Query all logs from a specific namespace query='{namespace="production"}' # Query with label filters query='{app="tidb", component="tikv"} |= "error"' """ try: await get_valid_server_auth() try: request = LokiQueryRangeRequest( query=query, start=start, end=end, cluster_id=cluster_id.strip(), env=env.strip(), deploy_type=deploy_type.strip(), limit=limit, direction=direction, step=step, ) except (ValueError, PydanticValidationError) as e: raise ValidationError(f"Invalid Loki range query parameters: {str(e)}") from e client, region = await get_loki_client_for_cluster( cluster_id=request.cluster_id, env=request.env, deploy_type=request.deploy_type, timeout=30.0, ) enriched_query = add_env_to_query(request.query, request.env) logger.info(f"Enriched Loki query: {enriched_query}") response = await client.query_range( query=enriched_query, start=request.start, end=request.end, limit=request.limit, direction=request.direction, step=request.step, ) return tool_text_response(json.dumps(response, ensure_ascii=False)) except ( AuthServiceError, AuthorizationError, ValidationError, NetworkError, LokiTimeoutError, LokiAPIError, ) as e: return tool_text_response(format_tool_error(e)) except Exception as e: return tool_text_response(format_tool_error(e))