"""
Query validation tool for the Text-to-GraphQL MCP Server.
"""
from typing import Dict, Any, Optional, List, Union
from ..logger import logger
from ..types import AgentState
import json
from graphql import parse, validate, GraphQLError
def validate_gql_query(schema, query: str) -> tuple[bool, Union[list[str], GraphQLError]]:
try:
query_ast = parse(query)
errors = validate(schema, query_ast)
if errors:
return False, errors
return True, []
except Exception as e:
return False, [str(e)]
async def query_validation(state: AgentState) -> AgentState:
"""
Validates GraphQL queries for correctness and optimization.
Given a constructed GraphQL query and schema information:
- Checks for syntax errors in the query
- Verifies that all referenced types and fields exist in the schema
- Ensures required fields have proper arguments
- Checks for type consistency in variables and arguments
- Identifies potential performance issues
- Suggests optimizations where appropriate
- Provides human-readable error and suggestion messages
"""
state["current_step"] = "query_validation"
logger.json("INFO", "Query Validation started", {
"state": state
})
try:
# Get the query, intent, and schema from the state
query = state.get("query", "")
intent = state.get("intent")
schema = state.get("schema")
if not query:
logger.json("WARNING", "No query provided for validation", {
"tool": "query_validation",
"error": "missing_query"
})
state["tool_error"] = "No query provided for validation"
return state
if not intent or not schema:
logger.json("WARNING", "Missing intent or schema for validation", {
"tool": "query_validation",
"error": "missing_prerequisites",
"missing_fields": [
field for field in ["intent", "schema"]
if not state.get(field)
]
})
state["tool_error"] = "Missing intent or schema for query validation"
return state
# Log the query being validated
logger.json("INFO", "Validating GraphQL query", {
"tool": "query_validation",
"intent": intent,
"query_preview": query[:100] + ("..." if len(query) > 100 else ""),
"schema_available": bool(schema)
})
# Validate the query
is_valid, errors = validate_gql_query(schema, query)
# Convert errors to string representation for logging
error_strings = [str(err) for err in errors] if errors else []
validation_result = {
"is_valid": is_valid,
"errors": error_strings,
}
# Store the validation result in the state
state["query_validation_result"] = validation_result
# Log the validation result with appropriate level based on validity
log_level = "INFO" if is_valid else "WARNING"
logger.json(log_level, "Query validation result", {
"tool": "query_validation",
"is_valid": is_valid,
"error_count": len(error_strings),
"errors": error_strings[:3] + (["..."] if len(error_strings) > 3 else [])
})
return state
except Exception as e:
error_info = {
"tool": "query_validation",
"error_type": type(e).__name__,
"error_message": str(e)
}
logger.json("ERROR", "Error in query validation", error_info)
state["tool_error"] = f"Query validation failed: {str(e)}"
return state