mcp-proxy-adapter 2.1.17__py3-none-any.whl → 3.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. examples/__init__.py +19 -0
  2. examples/anti_patterns/README.md +51 -0
  3. examples/anti_patterns/__init__.py +9 -0
  4. examples/anti_patterns/bad_design/README.md +72 -0
  5. examples/anti_patterns/bad_design/global_state.py +170 -0
  6. examples/anti_patterns/bad_design/monolithic_command.py +272 -0
  7. examples/basic_example/README.md +245 -0
  8. examples/basic_example/__init__.py +8 -0
  9. examples/basic_example/commands/__init__.py +5 -0
  10. examples/basic_example/commands/echo_command.py +95 -0
  11. examples/basic_example/commands/math_command.py +151 -0
  12. examples/basic_example/commands/time_command.py +152 -0
  13. examples/basic_example/config.json +25 -0
  14. examples/basic_example/docs/EN/README.md +177 -0
  15. examples/basic_example/docs/RU/README.md +177 -0
  16. examples/basic_example/server.py +151 -0
  17. examples/basic_example/tests/conftest.py +243 -0
  18. examples/commands/echo_command.py +52 -0
  19. examples/commands/echo_result.py +65 -0
  20. examples/commands/get_date_command.py +98 -0
  21. examples/commands/new_uuid4_command.py +91 -0
  22. examples/complete_example/Dockerfile +24 -0
  23. examples/complete_example/README.md +92 -0
  24. examples/complete_example/__init__.py +8 -0
  25. examples/complete_example/commands/__init__.py +5 -0
  26. examples/complete_example/commands/system_command.py +328 -0
  27. examples/complete_example/config.json +41 -0
  28. examples/complete_example/configs/config.dev.yaml +40 -0
  29. examples/complete_example/configs/config.docker.yaml +40 -0
  30. examples/complete_example/docker-compose.yml +35 -0
  31. examples/complete_example/requirements.txt +20 -0
  32. examples/complete_example/server.py +139 -0
  33. examples/minimal_example/README.md +65 -0
  34. examples/minimal_example/__init__.py +8 -0
  35. examples/minimal_example/config.json +14 -0
  36. examples/minimal_example/main.py +136 -0
  37. examples/minimal_example/simple_server.py +163 -0
  38. examples/minimal_example/tests/conftest.py +171 -0
  39. examples/minimal_example/tests/test_hello_command.py +111 -0
  40. examples/minimal_example/tests/test_integration.py +181 -0
  41. examples/server.py +69 -0
  42. examples/simple_server.py +128 -0
  43. examples/test_server.py +134 -0
  44. examples/tool_description_example.py +82 -0
  45. mcp_proxy_adapter/__init__.py +33 -1
  46. mcp_proxy_adapter/api/__init__.py +0 -0
  47. mcp_proxy_adapter/api/app.py +391 -0
  48. mcp_proxy_adapter/api/handlers.py +229 -0
  49. mcp_proxy_adapter/api/middleware/__init__.py +49 -0
  50. mcp_proxy_adapter/api/middleware/auth.py +146 -0
  51. mcp_proxy_adapter/api/middleware/base.py +79 -0
  52. mcp_proxy_adapter/api/middleware/error_handling.py +198 -0
  53. mcp_proxy_adapter/api/middleware/logging.py +96 -0
  54. mcp_proxy_adapter/api/middleware/performance.py +83 -0
  55. mcp_proxy_adapter/api/middleware/rate_limit.py +152 -0
  56. mcp_proxy_adapter/api/schemas.py +305 -0
  57. mcp_proxy_adapter/api/tool_integration.py +223 -0
  58. mcp_proxy_adapter/api/tools.py +198 -0
  59. mcp_proxy_adapter/commands/__init__.py +19 -0
  60. mcp_proxy_adapter/commands/base.py +301 -0
  61. mcp_proxy_adapter/commands/command_registry.py +231 -0
  62. mcp_proxy_adapter/commands/config_command.py +113 -0
  63. mcp_proxy_adapter/commands/health_command.py +136 -0
  64. mcp_proxy_adapter/commands/help_command.py +193 -0
  65. mcp_proxy_adapter/commands/result.py +215 -0
  66. mcp_proxy_adapter/config.py +195 -0
  67. mcp_proxy_adapter/core/__init__.py +0 -0
  68. mcp_proxy_adapter/core/errors.py +173 -0
  69. mcp_proxy_adapter/core/logging.py +205 -0
  70. mcp_proxy_adapter/core/utils.py +138 -0
  71. mcp_proxy_adapter/custom_openapi.py +125 -0
  72. mcp_proxy_adapter/openapi.py +403 -0
  73. mcp_proxy_adapter/py.typed +0 -0
  74. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  75. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  76. mcp_proxy_adapter/tests/__init__.py +0 -0
  77. mcp_proxy_adapter/tests/api/__init__.py +3 -0
  78. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +115 -0
  79. mcp_proxy_adapter/tests/api/test_middleware.py +336 -0
  80. mcp_proxy_adapter/tests/commands/__init__.py +3 -0
  81. mcp_proxy_adapter/tests/commands/test_config_command.py +211 -0
  82. mcp_proxy_adapter/tests/commands/test_echo_command.py +127 -0
  83. mcp_proxy_adapter/tests/commands/test_help_command.py +133 -0
  84. mcp_proxy_adapter/tests/conftest.py +131 -0
  85. mcp_proxy_adapter/tests/functional/__init__.py +3 -0
  86. mcp_proxy_adapter/tests/functional/test_api.py +235 -0
  87. mcp_proxy_adapter/tests/integration/__init__.py +3 -0
  88. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +130 -0
  89. mcp_proxy_adapter/tests/integration/test_integration.py +255 -0
  90. mcp_proxy_adapter/tests/performance/__init__.py +3 -0
  91. mcp_proxy_adapter/tests/performance/test_performance.py +189 -0
  92. mcp_proxy_adapter/tests/stubs/__init__.py +10 -0
  93. mcp_proxy_adapter/tests/stubs/echo_command.py +104 -0
  94. mcp_proxy_adapter/tests/test_api_endpoints.py +271 -0
  95. mcp_proxy_adapter/tests/test_api_handlers.py +289 -0
  96. mcp_proxy_adapter/tests/test_base_command.py +123 -0
  97. mcp_proxy_adapter/tests/test_batch_requests.py +117 -0
  98. mcp_proxy_adapter/tests/test_command_registry.py +245 -0
  99. mcp_proxy_adapter/tests/test_config.py +127 -0
  100. mcp_proxy_adapter/tests/test_utils.py +65 -0
  101. mcp_proxy_adapter/tests/unit/__init__.py +3 -0
  102. mcp_proxy_adapter/tests/unit/test_base_command.py +130 -0
  103. mcp_proxy_adapter/tests/unit/test_config.py +217 -0
  104. mcp_proxy_adapter/version.py +3 -0
  105. mcp_proxy_adapter-3.0.1.dist-info/METADATA +200 -0
  106. mcp_proxy_adapter-3.0.1.dist-info/RECORD +109 -0
  107. {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/top_level.txt +1 -0
  108. mcp_proxy_adapter/adapter.py +0 -697
  109. mcp_proxy_adapter/analyzers/__init__.py +0 -1
  110. mcp_proxy_adapter/analyzers/docstring_analyzer.py +0 -199
  111. mcp_proxy_adapter/analyzers/type_analyzer.py +0 -151
  112. mcp_proxy_adapter/dispatchers/__init__.py +0 -1
  113. mcp_proxy_adapter/dispatchers/base_dispatcher.py +0 -85
  114. mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +0 -262
  115. mcp_proxy_adapter/examples/analyze_config.py +0 -141
  116. mcp_proxy_adapter/examples/basic_integration.py +0 -155
  117. mcp_proxy_adapter/examples/docstring_and_schema_example.py +0 -69
  118. mcp_proxy_adapter/examples/extension_example.py +0 -72
  119. mcp_proxy_adapter/examples/help_best_practices.py +0 -67
  120. mcp_proxy_adapter/examples/help_usage.py +0 -64
  121. mcp_proxy_adapter/examples/mcp_proxy_client.py +0 -131
  122. mcp_proxy_adapter/examples/openapi_server.py +0 -383
  123. mcp_proxy_adapter/examples/project_structure_example.py +0 -47
  124. mcp_proxy_adapter/examples/testing_example.py +0 -64
  125. mcp_proxy_adapter/models.py +0 -47
  126. mcp_proxy_adapter/registry.py +0 -439
  127. mcp_proxy_adapter/schema.py +0 -257
  128. mcp_proxy_adapter/testing_utils.py +0 -112
  129. mcp_proxy_adapter/validators/__init__.py +0 -1
  130. mcp_proxy_adapter/validators/docstring_validator.py +0 -75
  131. mcp_proxy_adapter/validators/metadata_validator.py +0 -76
  132. mcp_proxy_adapter-2.1.17.dist-info/METADATA +0 -376
  133. mcp_proxy_adapter-2.1.17.dist-info/RECORD +0 -30
  134. {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/WHEEL +0 -0
  135. {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,215 @@
1
+ """
2
+ Module with base classes for command results.
3
+ """
4
+
5
+ import json
6
+ from abc import ABC, abstractmethod
7
+ from typing import Any, Dict, List, Optional, Type, TypeVar, Union
8
+
9
+ T = TypeVar("T", bound="CommandResult")
10
+
11
+
12
+ class CommandResult(ABC):
13
+ """
14
+ Base abstract class for command execution results.
15
+ """
16
+
17
+ @abstractmethod
18
+ def to_dict(self) -> Dict[str, Any]:
19
+ """
20
+ Converts result to dictionary for serialization.
21
+
22
+ Returns:
23
+ Dictionary with result data.
24
+ """
25
+ pass
26
+
27
+ @classmethod
28
+ @abstractmethod
29
+ def get_schema(cls) -> Dict[str, Any]:
30
+ """
31
+ Returns JSON schema for result validation.
32
+
33
+ Returns:
34
+ Dictionary with JSON schema.
35
+ """
36
+ pass
37
+
38
+ def to_json(self, indent: Optional[int] = None) -> str:
39
+ """
40
+ Converts result to JSON string.
41
+
42
+ Args:
43
+ indent: Indentation for JSON formatting.
44
+
45
+ Returns:
46
+ JSON string with result.
47
+ """
48
+ return json.dumps(self.to_dict(), ensure_ascii=False, indent=indent)
49
+
50
+ @classmethod
51
+ def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
52
+ """
53
+ Creates result instance from dictionary.
54
+ This method must be overridden in subclasses.
55
+
56
+ Args:
57
+ data: Dictionary with result data.
58
+
59
+ Returns:
60
+ Result instance.
61
+ """
62
+ raise NotImplementedError("Method from_dict must be implemented in subclasses")
63
+
64
+
65
+ class SuccessResult(CommandResult):
66
+ """
67
+ Base class for successful command results.
68
+ """
69
+
70
+ def __init__(self, data: Optional[Dict[str, Any]] = None, message: Optional[str] = None):
71
+ """
72
+ Initialize successful result.
73
+
74
+ Args:
75
+ data: Result data.
76
+ message: Result message.
77
+ """
78
+ self.data = data or {}
79
+ self.message = message
80
+
81
+ def to_dict(self) -> Dict[str, Any]:
82
+ """
83
+ Converts result to dictionary for serialization.
84
+
85
+ Returns:
86
+ Dictionary with result data.
87
+ """
88
+ result = {"success": True}
89
+ if self.data:
90
+ result["data"] = self.data
91
+ if self.message:
92
+ result["message"] = self.message
93
+ return result
94
+
95
+ @classmethod
96
+ def get_schema(cls) -> Dict[str, Any]:
97
+ """
98
+ Returns JSON schema for result validation.
99
+
100
+ Returns:
101
+ Dictionary with JSON schema.
102
+ """
103
+ return {
104
+ "type": "object",
105
+ "properties": {
106
+ "success": {"type": "boolean"},
107
+ "data": {"type": "object"},
108
+ "message": {"type": "string"}
109
+ },
110
+ "required": ["success"]
111
+ }
112
+
113
+ @classmethod
114
+ def from_dict(cls, data: Dict[str, Any]) -> "SuccessResult":
115
+ """
116
+ Creates successful result instance from dictionary.
117
+
118
+ Args:
119
+ data: Dictionary with result data.
120
+
121
+ Returns:
122
+ Successful result instance.
123
+ """
124
+ return cls(
125
+ data=data.get("data"),
126
+ message=data.get("message")
127
+ )
128
+
129
+
130
+ class ErrorResult(CommandResult):
131
+ """
132
+ Base class for command results with error.
133
+
134
+ This class follows the JSON-RPC 2.0 error object format:
135
+ https://www.jsonrpc.org/specification#error_object
136
+ """
137
+
138
+ def __init__(
139
+ self,
140
+ message: str,
141
+ code: int = -32000,
142
+ details: Optional[Dict[str, Any]] = None
143
+ ):
144
+ """
145
+ Initialize error result.
146
+
147
+ Args:
148
+ message: Error message.
149
+ code: Error code (following JSON-RPC 2.0 spec).
150
+ details: Additional error details.
151
+ """
152
+ self.message = message
153
+ self.code = code
154
+ self.details = details or {}
155
+
156
+ def to_dict(self) -> Dict[str, Any]:
157
+ """
158
+ Converts result to dictionary for serialization.
159
+
160
+ Returns:
161
+ Dictionary with result data in JSON-RPC 2.0 error format.
162
+ """
163
+ result = {
164
+ "success": False,
165
+ "error": {
166
+ "code": self.code,
167
+ "message": self.message
168
+ }
169
+ }
170
+ if self.details:
171
+ result["error"]["data"] = self.details
172
+ return result
173
+
174
+ @classmethod
175
+ def get_schema(cls) -> Dict[str, Any]:
176
+ """
177
+ Returns JSON schema for result validation.
178
+
179
+ Returns:
180
+ Dictionary with JSON schema.
181
+ """
182
+ return {
183
+ "type": "object",
184
+ "properties": {
185
+ "success": {"type": "boolean"},
186
+ "error": {
187
+ "type": "object",
188
+ "properties": {
189
+ "code": {"type": "integer"},
190
+ "message": {"type": "string"},
191
+ "data": {"type": "object"}
192
+ },
193
+ "required": ["code", "message"]
194
+ }
195
+ },
196
+ "required": ["success", "error"]
197
+ }
198
+
199
+ @classmethod
200
+ def from_dict(cls, data: Dict[str, Any]) -> "ErrorResult":
201
+ """
202
+ Creates error result instance from dictionary.
203
+
204
+ Args:
205
+ data: Dictionary with result data.
206
+
207
+ Returns:
208
+ Error result instance.
209
+ """
210
+ error = data.get("error", {})
211
+ return cls(
212
+ message=error.get("message", "Unknown error"),
213
+ code=error.get("code", -32000),
214
+ details=error.get("data")
215
+ )
@@ -0,0 +1,195 @@
1
+ """
2
+ Module for microservice configuration management.
3
+ """
4
+
5
+ import json
6
+ import os
7
+ from pathlib import Path
8
+ from typing import Any, Dict, Optional
9
+
10
+
11
+ class Config:
12
+ """
13
+ Configuration management class for the microservice.
14
+ Allows loading settings from configuration file and environment variables.
15
+ """
16
+
17
+ def __init__(self, config_path: Optional[str] = None):
18
+ """
19
+ Initialize configuration.
20
+
21
+ Args:
22
+ config_path: Path to configuration file. If not specified, "./config.json" is used.
23
+ """
24
+ self.config_path = config_path or "./config.json"
25
+ self.config_data: Dict[str, Any] = {}
26
+ self.load_config()
27
+
28
+ def load_config(self) -> None:
29
+ """
30
+ Load configuration from file and environment variables.
31
+ """
32
+ # Set default config values
33
+ self.config_data = {
34
+ "server": {
35
+ "host": "0.0.0.0",
36
+ "port": 8000,
37
+ "debug": False,
38
+ "log_level": "INFO"
39
+ },
40
+ "logging": {
41
+ "level": "INFO",
42
+ "file": None
43
+ }
44
+ }
45
+
46
+ # Try to load configuration from file
47
+ if os.path.exists(self.config_path):
48
+ try:
49
+ with open(self.config_path, 'r', encoding='utf-8') as f:
50
+ file_config = json.load(f)
51
+ self._update_nested_dict(self.config_data, file_config)
52
+ except Exception as e:
53
+ print(f"Error loading config from {self.config_path}: {e}")
54
+
55
+ # Load configuration from environment variables
56
+ self._load_env_variables()
57
+
58
+ def load_from_file(self, config_path: str) -> None:
59
+ """
60
+ Load configuration from the specified file.
61
+
62
+ Args:
63
+ config_path: Path to configuration file.
64
+ """
65
+ self.config_path = config_path
66
+ self.load_config()
67
+
68
+ def _load_env_variables(self) -> None:
69
+ """
70
+ Load configuration from environment variables.
71
+ Environment variables should be in format SERVICE_SECTION_KEY=value.
72
+ For example, SERVICE_SERVER_PORT=8080.
73
+ """
74
+ prefix = "SERVICE_"
75
+ for key, value in os.environ.items():
76
+ if key.startswith(prefix):
77
+ parts = key[len(prefix):].lower().split("_", 1)
78
+ if len(parts) == 2:
79
+ section, param = parts
80
+ if section not in self.config_data:
81
+ self.config_data[section] = {}
82
+ self.config_data[section][param] = self._convert_env_value(value)
83
+
84
+ def _convert_env_value(self, value: str) -> Any:
85
+ """
86
+ Convert environment variable value to appropriate type.
87
+
88
+ Args:
89
+ value: Value as string
90
+
91
+ Returns:
92
+ Converted value
93
+ """
94
+ # Try to convert to appropriate type
95
+ if value.lower() == "true":
96
+ return True
97
+ elif value.lower() == "false":
98
+ return False
99
+ elif value.isdigit():
100
+ return int(value)
101
+ else:
102
+ try:
103
+ return float(value)
104
+ except ValueError:
105
+ return value
106
+
107
+ def get(self, key: str, default: Any = None) -> Any:
108
+ """
109
+ Get configuration value for key.
110
+
111
+ Args:
112
+ key: Configuration key in format "section.param"
113
+ default: Default value if key not found
114
+
115
+ Returns:
116
+ Configuration value
117
+ """
118
+ parts = key.split(".")
119
+
120
+ # Get value from config
121
+ value = self.config_data
122
+ for part in parts:
123
+ if not isinstance(value, dict) or part not in value:
124
+ return default
125
+ value = value[part]
126
+
127
+ return value
128
+
129
+ def get_all(self) -> Dict[str, Any]:
130
+ """
131
+ Get all configuration values.
132
+
133
+ Returns:
134
+ Dictionary with all configuration values
135
+ """
136
+ return self.config_data.copy()
137
+
138
+ def set(self, key: str, value: Any) -> None:
139
+ """
140
+ Set configuration value for key.
141
+
142
+ Args:
143
+ key: Configuration key in format "section.param"
144
+ value: Configuration value
145
+ """
146
+ parts = key.split(".")
147
+ if len(parts) == 1:
148
+ self.config_data[key] = value
149
+ else:
150
+ section = parts[0]
151
+ param = ".".join(parts[1:])
152
+
153
+ if section not in self.config_data:
154
+ self.config_data[section] = {}
155
+
156
+ current = self.config_data[section]
157
+ for part in parts[1:-1]:
158
+ if part not in current:
159
+ current[part] = {}
160
+ current = current[part]
161
+
162
+ current[parts[-1]] = value
163
+
164
+ def save(self, path: Optional[str] = None) -> None:
165
+ """
166
+ Save configuration to file.
167
+
168
+ Args:
169
+ path: Path to configuration file. If not specified, self.config_path is used.
170
+ """
171
+ save_path = path or self.config_path
172
+ with open(save_path, 'w', encoding='utf-8') as f:
173
+ json.dump(self.config_data, f, indent=2)
174
+
175
+ def _update_nested_dict(self, d: Dict, u: Dict) -> Dict:
176
+ """
177
+ Update nested dictionary recursively.
178
+
179
+ Args:
180
+ d: Dictionary to update
181
+ u: Dictionary with new values
182
+
183
+ Returns:
184
+ Updated dictionary
185
+ """
186
+ for k, v in u.items():
187
+ if isinstance(v, dict) and k in d and isinstance(d[k], dict):
188
+ self._update_nested_dict(d[k], v)
189
+ else:
190
+ d[k] = v
191
+ return d
192
+
193
+
194
+ # Singleton instance
195
+ config = Config()
File without changes
@@ -0,0 +1,173 @@
1
+ """
2
+ Module for defining errors and exceptions for the microservice.
3
+ """
4
+
5
+ from typing import Any, Dict, List, Optional, Union
6
+
7
+
8
+ class MicroserviceError(Exception):
9
+ """
10
+ Base class for all microservice exceptions.
11
+
12
+ Attributes:
13
+ message: Error message.
14
+ code: Error code.
15
+ data: Additional error data.
16
+ """
17
+ def __init__(self, message: str, code: int = -32000, data: Optional[Dict[str, Any]] = None):
18
+ """
19
+ Initialize the error.
20
+
21
+ Args:
22
+ message: Error message.
23
+ code: Error code according to JSON-RPC standard.
24
+ data: Additional error data.
25
+ """
26
+ self.message = message
27
+ self.code = code
28
+ self.data = data or {}
29
+ super().__init__(message)
30
+
31
+ def to_dict(self) -> Dict[str, Any]:
32
+ """
33
+ Converts the error to a dictionary for JSON-RPC response.
34
+
35
+ Returns:
36
+ Dictionary with error information.
37
+ """
38
+ result = {
39
+ "code": self.code,
40
+ "message": self.message
41
+ }
42
+
43
+ if self.data:
44
+ result["data"] = self.data
45
+
46
+ return result
47
+
48
+
49
+ class ParseError(MicroserviceError):
50
+ """
51
+ Error while parsing JSON request.
52
+ JSON-RPC Error code: -32700
53
+ """
54
+ def __init__(self, message: str = "Parse error", data: Optional[Dict[str, Any]] = None):
55
+ super().__init__(message, code=-32700, data=data)
56
+
57
+
58
+ class InvalidRequestError(MicroserviceError):
59
+ """
60
+ Invalid JSON-RPC request format.
61
+ JSON-RPC Error code: -32600
62
+ """
63
+ def __init__(self, message: str = "Invalid Request", data: Optional[Dict[str, Any]] = None):
64
+ super().__init__(message, code=-32600, data=data)
65
+
66
+
67
+ class MethodNotFoundError(MicroserviceError):
68
+ """
69
+ Method not found error.
70
+ JSON-RPC Error code: -32601
71
+ """
72
+ def __init__(self, message: str = "Method not found", data: Optional[Dict[str, Any]] = None):
73
+ super().__init__(message, code=-32601, data=data)
74
+
75
+
76
+ class InvalidParamsError(MicroserviceError):
77
+ """
78
+ Invalid method parameters.
79
+ JSON-RPC Error code: -32602
80
+ """
81
+ def __init__(self, message: str = "Invalid params", data: Optional[Dict[str, Any]] = None):
82
+ super().__init__(message, code=-32602, data=data)
83
+
84
+
85
+ class InternalError(MicroserviceError):
86
+ """
87
+ Internal server error.
88
+ JSON-RPC Error code: -32603
89
+ """
90
+ def __init__(self, message: str = "Internal error", data: Optional[Dict[str, Any]] = None):
91
+ super().__init__(message, code=-32603, data=data)
92
+
93
+
94
+ class ValidationError(MicroserviceError):
95
+ """
96
+ Input data validation error.
97
+ JSON-RPC Error code: -32602 (using Invalid params code)
98
+ """
99
+ def __init__(self, message: str = "Validation error", data: Optional[Dict[str, Any]] = None):
100
+ super().__init__(message, code=-32602, data=data)
101
+
102
+
103
+ class CommandError(MicroserviceError):
104
+ """
105
+ Command execution error.
106
+ JSON-RPC Error code: -32000 (server error)
107
+ """
108
+ def __init__(self, message: str = "Command execution error", data: Optional[Dict[str, Any]] = None):
109
+ super().__init__(message, code=-32000, data=data)
110
+
111
+
112
+ class NotFoundError(MicroserviceError):
113
+ """
114
+ "Not found" error.
115
+ JSON-RPC Error code: -32601 (using Method not found code)
116
+ """
117
+ def __init__(self, message: str = "Resource not found", data: Optional[Dict[str, Any]] = None):
118
+ super().__init__(message, code=-32601, data=data)
119
+
120
+
121
+ class ConfigurationError(MicroserviceError):
122
+ """
123
+ Configuration error.
124
+ JSON-RPC Error code: -32603 (using Internal error code)
125
+ """
126
+ def __init__(self, message: str = "Configuration error", data: Optional[Dict[str, Any]] = None):
127
+ super().__init__(message, code=-32603, data=data)
128
+
129
+
130
+ class AuthenticationError(MicroserviceError):
131
+ """
132
+ Authentication error.
133
+ JSON-RPC Error code: -32001 (server error)
134
+ """
135
+ def __init__(self, message: str = "Authentication error", data: Optional[Dict[str, Any]] = None):
136
+ super().__init__(message, code=-32001, data=data)
137
+
138
+
139
+ class AuthorizationError(MicroserviceError):
140
+ """
141
+ Authorization error.
142
+ JSON-RPC Error code: -32002 (server error)
143
+ """
144
+ def __init__(self, message: str = "Authorization error", data: Optional[Dict[str, Any]] = None):
145
+ super().__init__(message, code=-32002, data=data)
146
+
147
+
148
+ class TimeoutError(MicroserviceError):
149
+ """
150
+ Timeout error.
151
+ JSON-RPC Error code: -32003 (server error)
152
+ """
153
+ def __init__(self, message: str = "Timeout error", data: Optional[Dict[str, Any]] = None):
154
+ super().__init__(message, code=-32003, data=data)
155
+
156
+
157
+ def format_validation_errors(errors: List[Dict[str, Any]]) -> Dict[str, Any]:
158
+ """
159
+ Formats validation errors into a standard format.
160
+
161
+ Args:
162
+ errors: List of validation errors.
163
+
164
+ Returns:
165
+ Formatted validation errors.
166
+ """
167
+ formatted_errors = {}
168
+ for error in errors:
169
+ loc = error.get("loc", [])
170
+ field = ".".join(str(item) for item in loc)
171
+ msg = error.get("msg", "Validation error")
172
+ formatted_errors[field] = msg
173
+ return formatted_errors