"""JSON-RPC error envelope helpers for the Muse MCP server (§KD-5a.0).""" from __future__ import annotations from typing import Any from muse.core.validation import sanitize_display # JSON-RPC 2.0 standard codes PARSE_ERROR = -32700 INVALID_REQUEST = -32600 METHOD_NOT_FOUND = -32601 INVALID_PARAMS = -32602 INTERNAL_ERROR = -32603 # Application-level tool error (result carries reason in data) TOOL_ERROR = -32001 class MCPApplicationError(Exception): """Structured tool/resource error with a stable ``reason`` token.""" def __init__( self, reason: str, message: str, *, detail: str | None = None, ) -> None: self.reason = reason self.message = sanitize_display(message) self.detail = sanitize_display(detail) if detail else None super().__init__(message) def to_data(self) -> dict[str, str]: data: dict[str, str] = {"reason": self.reason} if self.detail: data["detail"] = self.detail return data def error_response( req_id: str | int | None, code: int, message: str, *, data: dict[str, Any] | None = None, ) -> dict[str, Any]: """Build a JSON-RPC 2.0 error object.""" payload: dict[str, Any] = { "jsonrpc": "2.0", "id": req_id, "error": { "code": code, "message": sanitize_display(message), }, } if data: payload["error"]["data"] = data return payload def success_response(req_id: str | int | None, result: Any) -> dict[str, Any]: """Build a JSON-RPC 2.0 success object.""" return {"jsonrpc": "2.0", "id": req_id, "result": result}