"""Error response models for MCP tool responses.
Provides structured error handling with clear distinction between error sources:
- comfyui: Errors from ComfyUI backend (API failures, node errors)
- mcp: Errors from MCP server logic (validation, processing)
- validation: Invalid user input or parameters
"""
from dataclasses import dataclass
from typing import Any, Literal
@dataclass
class ToolError:
"""Structured error response for MCP tools.
Use as a builder to create consistent error dictionaries that distinguish
between MCP server errors and backend service errors.
Example:
>>> error = ToolError.from_comfyui(
... "Node 'KSampler' not found",
... response={"error": "Invalid node type"}
... )
>>> return error.to_dict()
{
"error": "Node 'KSampler' not found",
"error_type": "comfyui",
"details": {"comfyui_response": {...}}
}
"""
error: str
error_type: Literal["comfyui", "mcp", "validation"]
details: dict[str, Any] | None = None
def to_dict(self) -> dict[str, Any]:
"""Convert to dictionary for MCP response.
Returns:
Dictionary with error, error_type, and optionally details
"""
result = {
"error": self.error,
"error_type": self.error_type,
}
if self.details:
result["details"] = self.details
return result
@classmethod
def from_comfyui(
cls,
message: str,
response: dict[str, Any] | None = None,
status_code: int | None = None,
) -> "ToolError":
"""Create error from ComfyUI backend failure.
Args:
message: Human-readable error description
response: Optional ComfyUI response data
status_code: Optional HTTP status code
Returns:
ToolError with error_type="comfyui"
"""
details = {}
if response is not None:
details["comfyui_response"] = response
if status_code is not None:
details["status_code"] = status_code
return cls(
error=message,
error_type="comfyui",
details=details if details else None,
)
@classmethod
def from_validation(
cls,
message: str,
field: str | None = None,
value: Any = None,
) -> "ToolError":
"""Create error from validation failure.
Args:
message: Human-readable error description
field: Optional field name that failed validation
value: Optional invalid value
Returns:
ToolError with error_type="validation"
"""
details = {}
if field is not None:
details["field"] = field
if value is not None:
details["value"] = value
return cls(
error=message,
error_type="validation",
details=details if details else None,
)
@classmethod
def from_mcp(
cls,
message: str,
exception: Exception | None = None,
) -> "ToolError":
"""Create error from MCP server internal failure.
Args:
message: Human-readable error description
exception: Optional exception that was raised
Returns:
ToolError with error_type="mcp"
"""
details = {}
if exception is not None:
details["exception_type"] = type(exception).__name__
details["exception_message"] = str(exception)
return cls(
error=message,
error_type="mcp",
details=details if details else None,
)