Coverage for src / lexigram / contracts / mcp / exceptions.py: 100%

54 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-19 05:41 +0800

1"""MCP exception hierarchy for the Lexigram framework. 

2 

3MCP-specific errors that can occur during MCP server operation. 

4These extend the base LexigramError for consistent error handling. 

5""" 

6 

7from __future__ import annotations 

8 

9from typing import Any 

10 

11from lexigram.contracts.exceptions.base import LexigramError 

12 

13 

14class MCPError(LexigramError): 

15 """Base exception for all MCP errors.""" 

16 

17 _code = "LEX_ERR_MCP_001" 

18 

19 def __init__(self, message: str = "MCP error", **kwargs: Any) -> None: 

20 super().__init__( 

21 message=message, 

22 **kwargs, 

23 ) 

24 

25 

26class MCPTransportError(MCPError): 

27 """Transport-level error (connection, I/O). 

28 

29 Raised when the MCP transport layer encounters errors 

30 such as connection failures, timeouts, or I/O errors. 

31 """ 

32 

33 _code = "LEX_ERR_MCP_002" 

34 

35 def __init__( 

36 self, 

37 message: str = "MCP transport error", 

38 *, 

39 transport_type: str | None = None, 

40 **kwargs: Any, 

41 ) -> None: 

42 details = kwargs.pop("details", {}) 

43 if transport_type: 

44 details["transport"] = transport_type 

45 super().__init__( 

46 message=message, 

47 details=details, 

48 **kwargs, 

49 ) 

50 

51 

52class MCPToolCallError(MCPError): 

53 """Tool call failed during MCP execution. 

54 

55 Raised when a tool invocation fails, either due to 

56 the tool not existing or raising an exception. 

57 """ 

58 

59 _code = "LEX_ERR_MCP_003" 

60 

61 def __init__( 

62 self, 

63 message: str = "MCP tool call failed", 

64 *, 

65 tool_name: str | None = None, 

66 **kwargs: Any, 

67 ) -> None: 

68 details = kwargs.pop("details", {}) 

69 if tool_name: 

70 details["tool"] = tool_name 

71 super().__init__( 

72 message=message, 

73 details=details, 

74 **kwargs, 

75 ) 

76 

77 

78class MCPResourceError(MCPError): 

79 """Resource read or list failed. 

80 

81 Raised when a resource operation fails, such as 

82 when a resource is not found or cannot be read. 

83 """ 

84 

85 _code = "LEX_ERR_MCP_004" 

86 

87 def __init__( 

88 self, 

89 message: str = "MCP resource error", 

90 *, 

91 uri: str | None = None, 

92 **kwargs: Any, 

93 ) -> None: 

94 details = kwargs.pop("details", {}) 

95 if uri: 

96 details["uri"] = uri 

97 super().__init__( 

98 message=message, 

99 details=details, 

100 **kwargs, 

101 ) 

102 

103 

104class MCPProtocolError(MCPError): 

105 """Protocol violation (malformed message, invalid state). 

106 

107 Raised when an MCP message violates the protocol specification, 

108 such as missing required fields or invalid JSON-RPC structure. 

109 """ 

110 

111 _code = "LEX_ERR_MCP_005" 

112 

113 def __init__( 

114 self, 

115 message: str = "MCP protocol error", 

116 *, 

117 details: dict[str, Any] | None = None, 

118 **kwargs: Any, 

119 ) -> None: 

120 super().__init__( 

121 message=message, 

122 details=details or {}, 

123 **kwargs, 

124 ) 

125 

126 

127class MCPMethodNotFoundError(MCPError): 

128 """Unknown MCP method requested by client. 

129 

130 Raised when the client requests an MCP method that 

131 the server does not support. 

132 """ 

133 

134 _code = "LEX_ERR_MCP_006" 

135 

136 def __init__( 

137 self, 

138 message: str = "MCP method not found", 

139 *, 

140 method: str | None = None, 

141 **kwargs: Any, 

142 ) -> None: 

143 details = kwargs.pop("details", {}) 

144 if method: 

145 details["method"] = method 

146 super().__init__( 

147 message=message, 

148 details=details, 

149 **kwargs, 

150 ) 

151 

152 

153class MCPPromptError(MCPError): 

154 """Prompt retrieval or list failed. 

155 

156 Raised when a prompt operation fails, such as 

157 when a prompt is not found or arguments are invalid. 

158 """ 

159 

160 _code = "LEX_ERR_MCP_007" 

161 

162 def __init__( 

163 self, 

164 message: str = "MCP prompt error", 

165 *, 

166 prompt_name: str | None = None, 

167 **kwargs: Any, 

168 ) -> None: 

169 details = kwargs.pop("details", {}) 

170 if prompt_name: 

171 details["prompt"] = prompt_name 

172 super().__init__( 

173 message=message, 

174 details=details, 

175 **kwargs, 

176 ) 

177 

178 

179class MCPInitializationError(MCPError): 

180 """MCP server initialization failed. 

181 

182 Raised when the MCP server cannot be initialized, 

183 usually due to missing required handlers or 

184 configuration errors. 

185 """ 

186 

187 _code = "LEX_ERR_MCP_008" 

188 

189 def __init__( 

190 self, 

191 message: str = "MCP initialization failed", 

192 *, 

193 reason: str | None = None, 

194 **kwargs: Any, 

195 ) -> None: 

196 details = kwargs.pop("details", {}) 

197 if reason: 

198 details["reason"] = reason 

199 super().__init__( 

200 message=message, 

201 details=details, 

202 **kwargs, 

203 ) 

204 

205 

206__all__ = [ 

207 "MCPError", 

208 "MCPInitializationError", 

209 "MCPMethodNotFoundError", 

210 "MCPPromptError", 

211 "MCPProtocolError", 

212 "MCPResourceError", 

213 "MCPToolCallError", 

214 "MCPTransportError", 

215]