mcp-proxy-adapter 6.9.43__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 (242) hide show
  1. mcp_proxy_adapter/__init__.py +47 -0
  2. mcp_proxy_adapter/__main__.py +13 -0
  3. mcp_proxy_adapter/api/__init__.py +0 -0
  4. mcp_proxy_adapter/api/app.py +66 -0
  5. mcp_proxy_adapter/api/core/__init__.py +18 -0
  6. mcp_proxy_adapter/api/core/app_factory.py +355 -0
  7. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  8. mcp_proxy_adapter/api/core/registration_context.py +356 -0
  9. mcp_proxy_adapter/api/core/registration_manager.py +266 -0
  10. mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
  11. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  12. mcp_proxy_adapter/api/handlers.py +181 -0
  13. mcp_proxy_adapter/api/middleware/__init__.py +21 -0
  14. mcp_proxy_adapter/api/middleware/base.py +54 -0
  15. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
  16. mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
  17. mcp_proxy_adapter/api/middleware/factory.py +147 -0
  18. mcp_proxy_adapter/api/middleware/logging.py +31 -0
  19. mcp_proxy_adapter/api/middleware/performance.py +51 -0
  20. mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
  21. mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
  22. mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
  23. mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
  24. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  25. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  26. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  27. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  28. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  29. mcp_proxy_adapter/api/schemas.py +270 -0
  30. mcp_proxy_adapter/api/tool_integration.py +131 -0
  31. mcp_proxy_adapter/api/tools.py +163 -0
  32. mcp_proxy_adapter/cli/__init__.py +12 -0
  33. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  34. mcp_proxy_adapter/cli/commands/client.py +100 -0
  35. mcp_proxy_adapter/cli/commands/config_generate.py +35 -0
  36. mcp_proxy_adapter/cli/commands/config_validate.py +74 -0
  37. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  38. mcp_proxy_adapter/cli/commands/server.py +174 -0
  39. mcp_proxy_adapter/cli/commands/sets.py +128 -0
  40. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  41. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  42. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  43. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  44. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  45. mcp_proxy_adapter/cli/main.py +63 -0
  46. mcp_proxy_adapter/cli/parser.py +338 -0
  47. mcp_proxy_adapter/cli/validators.py +231 -0
  48. mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
  49. mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
  50. mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
  51. mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
  52. mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
  53. mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
  54. mcp_proxy_adapter/client/proxy.py +123 -0
  55. mcp_proxy_adapter/commands/__init__.py +66 -0
  56. mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
  57. mcp_proxy_adapter/commands/base.py +389 -0
  58. mcp_proxy_adapter/commands/builtin_commands.py +30 -0
  59. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  60. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  61. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  62. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  63. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  64. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  65. mcp_proxy_adapter/commands/catalog_manager.py +97 -0
  66. mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
  67. mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
  68. mcp_proxy_adapter/commands/command_registry.py +298 -0
  69. mcp_proxy_adapter/commands/config_command.py +102 -0
  70. mcp_proxy_adapter/commands/dependency_container.py +40 -0
  71. mcp_proxy_adapter/commands/dependency_manager.py +143 -0
  72. mcp_proxy_adapter/commands/echo_command.py +48 -0
  73. mcp_proxy_adapter/commands/health_command.py +142 -0
  74. mcp_proxy_adapter/commands/help_command.py +175 -0
  75. mcp_proxy_adapter/commands/hooks.py +172 -0
  76. mcp_proxy_adapter/commands/key_management_command.py +484 -0
  77. mcp_proxy_adapter/commands/load_command.py +123 -0
  78. mcp_proxy_adapter/commands/plugins_command.py +246 -0
  79. mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
  80. mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
  81. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  82. mcp_proxy_adapter/commands/registration_status_command.py +76 -0
  83. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  84. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  85. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  86. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  87. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  88. mcp_proxy_adapter/commands/reload_command.py +136 -0
  89. mcp_proxy_adapter/commands/result.py +157 -0
  90. mcp_proxy_adapter/commands/role_test_command.py +99 -0
  91. mcp_proxy_adapter/commands/roles_management_command.py +502 -0
  92. mcp_proxy_adapter/commands/security_command.py +472 -0
  93. mcp_proxy_adapter/commands/settings_command.py +113 -0
  94. mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
  95. mcp_proxy_adapter/commands/token_management_command.py +500 -0
  96. mcp_proxy_adapter/commands/transport_management_command.py +129 -0
  97. mcp_proxy_adapter/commands/unload_command.py +92 -0
  98. mcp_proxy_adapter/config.py +32 -0
  99. mcp_proxy_adapter/core/__init__.py +8 -0
  100. mcp_proxy_adapter/core/app_factory.py +560 -0
  101. mcp_proxy_adapter/core/app_runner.py +318 -0
  102. mcp_proxy_adapter/core/auth_validator.py +508 -0
  103. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  104. mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
  105. mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
  106. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  107. mcp_proxy_adapter/core/certificate/certificate_validator.py +388 -0
  108. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
  109. mcp_proxy_adapter/core/certificate_utils.py +249 -0
  110. mcp_proxy_adapter/core/client.py +608 -0
  111. mcp_proxy_adapter/core/client_manager.py +271 -0
  112. mcp_proxy_adapter/core/client_security.py +411 -0
  113. mcp_proxy_adapter/core/config/__init__.py +18 -0
  114. mcp_proxy_adapter/core/config/config.py +237 -0
  115. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  116. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  117. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  118. mcp_proxy_adapter/core/config/simple_config.py +116 -0
  119. mcp_proxy_adapter/core/config/simple_config_generator.py +100 -0
  120. mcp_proxy_adapter/core/config/simple_config_validator.py +380 -0
  121. mcp_proxy_adapter/core/config_converter.py +252 -0
  122. mcp_proxy_adapter/core/config_validator.py +211 -0
  123. mcp_proxy_adapter/core/crl_utils.py +362 -0
  124. mcp_proxy_adapter/core/errors.py +276 -0
  125. mcp_proxy_adapter/core/job_manager.py +54 -0
  126. mcp_proxy_adapter/core/logging.py +250 -0
  127. mcp_proxy_adapter/core/mtls_asgi.py +140 -0
  128. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  129. mcp_proxy_adapter/core/mtls_proxy.py +229 -0
  130. mcp_proxy_adapter/core/mtls_server.py +154 -0
  131. mcp_proxy_adapter/core/protocol_manager.py +232 -0
  132. mcp_proxy_adapter/core/proxy/__init__.py +19 -0
  133. mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
  134. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
  135. mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
  136. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  137. mcp_proxy_adapter/core/proxy_client.py +184 -0
  138. mcp_proxy_adapter/core/proxy_registration.py +80 -0
  139. mcp_proxy_adapter/core/role_utils.py +103 -0
  140. mcp_proxy_adapter/core/security_adapter.py +343 -0
  141. mcp_proxy_adapter/core/security_factory.py +96 -0
  142. mcp_proxy_adapter/core/security_integration.py +342 -0
  143. mcp_proxy_adapter/core/server_adapter.py +251 -0
  144. mcp_proxy_adapter/core/server_engine.py +217 -0
  145. mcp_proxy_adapter/core/settings.py +260 -0
  146. mcp_proxy_adapter/core/signal_handler.py +107 -0
  147. mcp_proxy_adapter/core/ssl_utils.py +161 -0
  148. mcp_proxy_adapter/core/transport_manager.py +153 -0
  149. mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
  150. mcp_proxy_adapter/core/utils.py +101 -0
  151. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  152. mcp_proxy_adapter/core/validation/config_validator.py +219 -0
  153. mcp_proxy_adapter/core/validation/file_validator.py +131 -0
  154. mcp_proxy_adapter/core/validation/protocol_validator.py +190 -0
  155. mcp_proxy_adapter/core/validation/security_validator.py +140 -0
  156. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  157. mcp_proxy_adapter/custom_openapi.py +58 -0
  158. mcp_proxy_adapter/examples/__init__.py +16 -0
  159. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  160. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  161. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  162. mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
  163. mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
  164. mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
  165. mcp_proxy_adapter/examples/check_config.py +413 -0
  166. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  167. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  168. mcp_proxy_adapter/examples/config_builder.py +234 -0
  169. mcp_proxy_adapter/examples/config_cli.py +282 -0
  170. mcp_proxy_adapter/examples/create_test_configs.py +174 -0
  171. mcp_proxy_adapter/examples/debug_request_state.py +130 -0
  172. mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
  173. mcp_proxy_adapter/examples/demo_client.py +287 -0
  174. mcp_proxy_adapter/examples/full_application/__init__.py +13 -0
  175. mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
  176. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
  177. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
  178. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
  179. mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
  180. mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
  181. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
  182. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
  183. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
  184. mcp_proxy_adapter/examples/full_application/main.py +264 -0
  185. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +81 -0
  186. mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
  187. mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
  188. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
  189. mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
  190. mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
  191. mcp_proxy_adapter/examples/generate_config.py +502 -0
  192. mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
  193. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  194. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  195. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  196. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  197. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  198. mcp_proxy_adapter/examples/required_certificates.py +208 -0
  199. mcp_proxy_adapter/examples/run_example.py +77 -0
  200. mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
  201. mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
  202. mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
  203. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  204. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  205. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  206. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  207. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  208. mcp_proxy_adapter/examples/security_test_client.py +72 -0
  209. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  210. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  211. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  212. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  213. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  214. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  215. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  216. mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
  217. mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
  218. mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
  219. mcp_proxy_adapter/examples/test_config.py +205 -0
  220. mcp_proxy_adapter/examples/test_config_builder.py +110 -0
  221. mcp_proxy_adapter/examples/test_examples.py +308 -0
  222. mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
  223. mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
  224. mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
  225. mcp_proxy_adapter/examples/universal_client.py +674 -0
  226. mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
  227. mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
  228. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
  229. mcp_proxy_adapter/integrations/__init__.py +25 -0
  230. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  231. mcp_proxy_adapter/main.py +313 -0
  232. mcp_proxy_adapter/openapi.py +375 -0
  233. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  234. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  235. mcp_proxy_adapter/schemas/roles.json +37 -0
  236. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  237. mcp_proxy_adapter/version.py +5 -0
  238. mcp_proxy_adapter-6.9.43.dist-info/METADATA +739 -0
  239. mcp_proxy_adapter-6.9.43.dist-info/RECORD +242 -0
  240. mcp_proxy_adapter-6.9.43.dist-info/WHEEL +5 -0
  241. mcp_proxy_adapter-6.9.43.dist-info/entry_points.txt +12 -0
  242. mcp_proxy_adapter-6.9.43.dist-info/top_level.txt +1 -0
@@ -0,0 +1,276 @@
1
+ """
2
+ Module for defining errors and exceptions for the microservice.
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any, Dict, List, Optional
7
+
8
+
9
+ class MicroserviceError(Exception):
10
+ """
11
+ Base class for all microservice exceptions.
12
+
13
+ Attributes:
14
+ message: Error message.
15
+ code: Error code.
16
+ data: Additional error data.
17
+ """
18
+
19
+ def __init__(
20
+ self, message: str, code: int = -32000, data: Optional[Dict[str, Any]] = None
21
+ ):
22
+ """
23
+ Initialize the error.
24
+
25
+ Args:
26
+ message: Error message.
27
+ code: Error code according to JSON-RPC standard.
28
+ data: Additional error data.
29
+ """
30
+ self.message = message
31
+ self.code = code
32
+ self.data = data or {}
33
+ super().__init__(message)
34
+
35
+ def to_dict(self) -> Dict[str, Any]:
36
+ """Convert error to dictionary format."""
37
+ result = {
38
+ "code": self.code,
39
+ "message": self.message
40
+ }
41
+ if self.data:
42
+ result["data"] = self.data
43
+ return result
44
+
45
+
46
+
47
+ class ParseError(MicroserviceError):
48
+ """
49
+ Error while parsing JSON request.
50
+ JSON-RPC Error code: -32700
51
+ """
52
+
53
+ def __init__(
54
+ self, message: str = "Parse error", data: Optional[Dict[str, Any]] = None
55
+ ):
56
+ super().__init__(message, code=-32700, data=data)
57
+
58
+
59
+ class InvalidRequestError(MicroserviceError):
60
+ """
61
+ Invalid JSON-RPC request format.
62
+ JSON-RPC Error code: -32600
63
+ """
64
+
65
+ def __init__(
66
+ self, message: str = "Invalid Request", data: Optional[Dict[str, Any]] = None
67
+ ):
68
+ super().__init__(message, code=-32600, data=data)
69
+
70
+
71
+ class MethodNotFoundError(MicroserviceError):
72
+ """
73
+ Method not found error.
74
+ JSON-RPC Error code: -32601
75
+ """
76
+
77
+ def __init__(
78
+ self, message: str = "Method not found", data: Optional[Dict[str, Any]] = None
79
+ ):
80
+ super().__init__(message, code=-32601, data=data)
81
+
82
+
83
+ class InvalidParamsError(MicroserviceError):
84
+ """
85
+ Invalid method parameters.
86
+ JSON-RPC Error code: -32602
87
+ """
88
+
89
+ def __init__(
90
+ self, message: str = "Invalid params", data: Optional[Dict[str, Any]] = None
91
+ ):
92
+ super().__init__(message, code=-32602, data=data)
93
+
94
+
95
+ class InternalError(MicroserviceError):
96
+ """
97
+ Internal server error.
98
+ JSON-RPC Error code: -32603
99
+ """
100
+
101
+ def __init__(
102
+ self, message: str = "Internal error", data: Optional[Dict[str, Any]] = None
103
+ ):
104
+ super().__init__(message, code=-32603, data=data)
105
+
106
+
107
+ class ValidationError(MicroserviceError):
108
+ """
109
+ Input data validation error.
110
+ JSON-RPC Error code: -32602 (using Invalid params code)
111
+ """
112
+
113
+ def __init__(
114
+ self, message: str = "Validation error", data: Optional[Dict[str, Any]] = None
115
+ ):
116
+ super().__init__(message, code=-32602, data=data)
117
+
118
+
119
+ class CommandError(MicroserviceError):
120
+ """
121
+ Command execution error.
122
+ JSON-RPC Error code: -32000 (server error)
123
+ """
124
+
125
+ def __init__(
126
+ self,
127
+ message: str = "Command execution error",
128
+ data: Optional[Dict[str, Any]] = None,
129
+ ):
130
+ super().__init__(message, code=-32000, data=data)
131
+
132
+
133
+ class NotFoundError(MicroserviceError):
134
+ """
135
+ "Not found" error.
136
+ JSON-RPC Error code: -32601 (using Method not found code)
137
+ """
138
+
139
+ def __init__(
140
+ self, message: str = "Resource not found", data: Optional[Dict[str, Any]] = None
141
+ ):
142
+ super().__init__(message, code=-32601, data=data)
143
+
144
+
145
+ class ConfigurationError(MicroserviceError):
146
+ """
147
+ Configuration error.
148
+ JSON-RPC Error code: -32603 (using Internal error code)
149
+ """
150
+
151
+ def __init__(
152
+ self,
153
+ message: str = "Configuration error",
154
+ data: Optional[Dict[str, Any]] = None,
155
+ ):
156
+ super().__init__(message, code=-32603, data=data)
157
+
158
+
159
+ class AuthenticationError(MicroserviceError):
160
+ """
161
+ Authentication error.
162
+ JSON-RPC Error code: -32001 (server error)
163
+ """
164
+
165
+ def __init__(
166
+ self,
167
+ message: str = "Authentication error",
168
+ data: Optional[Dict[str, Any]] = None,
169
+ ):
170
+ super().__init__(message, code=-32001, data=data)
171
+
172
+
173
+ class AuthorizationError(MicroserviceError):
174
+ """
175
+ Authorization error.
176
+ JSON-RPC Error code: -32002 (server error)
177
+ """
178
+
179
+ def __init__(
180
+ self,
181
+ message: str = "Authorization error",
182
+ data: Optional[Dict[str, Any]] = None,
183
+ ):
184
+ super().__init__(message, code=-32002, data=data)
185
+
186
+
187
+ class TimeoutError(MicroserviceError):
188
+ """
189
+ Timeout error.
190
+ JSON-RPC Error code: -32003 (server error)
191
+ """
192
+
193
+ def __init__(
194
+ self, message: str = "Timeout error", data: Optional[Dict[str, Any]] = None
195
+ ):
196
+ super().__init__(message, code=-32003, data=data)
197
+
198
+
199
+
200
+
201
+ @dataclass
202
+ class ValidationResult:
203
+ """Result of configuration validation."""
204
+ level: str # "error", "warning", "info"
205
+ message: str
206
+ section: Optional[str] = None
207
+ key: Optional[str] = None
208
+ suggestion: Optional[str] = None
209
+
210
+
211
+ class ConfigError(MicroserviceError):
212
+ """Configuration validation error."""
213
+
214
+ def __init__(self, message: str, validation_results: Optional[List[ValidationResult]] = None):
215
+ """
216
+ Initialize configuration error.
217
+
218
+ Args:
219
+ message: Error message
220
+ validation_results: List of validation results that caused the error
221
+ """
222
+ super().__init__(message, code=-32001, data={"type": "configuration_error"})
223
+ self.validation_results = validation_results or []
224
+
225
+
226
+
227
+ class MissingConfigKeyError(ConfigError):
228
+ """Missing required configuration key."""
229
+
230
+ def __init__(self, key: str, section: str = None):
231
+ location = f"{section}.{key}" if section else key
232
+ message = f"Required configuration key '{location}' is missing"
233
+ super().__init__(message)
234
+ self.key = key
235
+ self.section = section
236
+
237
+
238
+ class InvalidConfigValueError(ConfigError):
239
+ """Invalid configuration value."""
240
+
241
+ def __init__(self, key: str, value: Any, expected_type: str, section: str = None):
242
+ location = f"{section}.{key}" if section else key
243
+ message = f"Invalid value for '{location}': got {type(value).__name__}, expected {expected_type}"
244
+ super().__init__(message)
245
+ self.key = key
246
+ self.section = section
247
+ self.value = value
248
+ self.expected_type = expected_type
249
+
250
+
251
+ class MissingConfigSectionError(ConfigError):
252
+ """Missing required configuration section."""
253
+
254
+ def __init__(self, section: str):
255
+ message = f"Required configuration section '{section}' is missing"
256
+ super().__init__(message)
257
+ self.section = section
258
+
259
+
260
+ class MissingConfigFileError(ConfigError):
261
+ """Missing configuration file."""
262
+
263
+ def __init__(self, file_path: str):
264
+ message = f"Configuration file '{file_path}' does not exist"
265
+ super().__init__(message)
266
+ self.file_path = file_path
267
+
268
+
269
+ class InvalidConfigFileError(ConfigError):
270
+ """Invalid configuration file format."""
271
+
272
+ def __init__(self, file_path: str, reason: str):
273
+ message = f"Invalid configuration file '{file_path}': {reason}"
274
+ super().__init__(message)
275
+ self.file_path = file_path
276
+ self.reason = reason
@@ -0,0 +1,54 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Simple in-memory job manager for long-running demo commands.
6
+ Not for production use.
7
+ """
8
+
9
+ import asyncio
10
+ import uuid
11
+ from typing import Any, Dict, Optional, Awaitable
12
+
13
+
14
+ class JobRecord:
15
+ def __init__(self, task: asyncio.Task):
16
+ self.task = task
17
+ self.status = "running"
18
+ self.result: Optional[Any] = None
19
+ self.error: Optional[str] = None
20
+
21
+
22
+ _jobs: Dict[str, JobRecord] = {}
23
+
24
+
25
+ def enqueue_coroutine(coro: Awaitable[Any]) -> str:
26
+ job_id = str(uuid.uuid4())
27
+ task = asyncio.create_task(_run_job(job_id, coro))
28
+ _jobs[job_id] = JobRecord(task)
29
+ return job_id
30
+
31
+
32
+ async def _run_job(job_id: str, coro):
33
+ rec = _jobs[job_id]
34
+ try:
35
+ rec.result = await coro
36
+ rec.status = "completed"
37
+ except Exception as exc: # noqa: BLE001
38
+ rec.error = str(exc)
39
+ rec.status = "failed"
40
+
41
+
42
+ def get_job_status(job_id: str) -> Dict[str, Any]:
43
+ rec = _jobs.get(job_id)
44
+ if not rec:
45
+ return {"exists": False}
46
+ return {
47
+ "exists": True,
48
+ "status": rec.status,
49
+ "done": rec.task.done(),
50
+ "result": rec.result,
51
+ "error": rec.error,
52
+ }
53
+
54
+
@@ -0,0 +1,250 @@
1
+ """
2
+ Module for configuring logging in the microservice.
3
+ """
4
+
5
+ import logging
6
+ import os
7
+ import sys
8
+ import uuid
9
+ from logging.handlers import RotatingFileHandler
10
+ from typing import Optional
11
+
12
+
13
+ class CustomFormatter(logging.Formatter):
14
+ """
15
+ Custom formatter for logs with colored output in console.
16
+ """
17
+
18
+ grey = "\x1b[38;20m"
19
+ yellow = "\x1b[33;20m"
20
+ red = "\x1b[31;20m"
21
+ bold_red = "\x1b[31;1m"
22
+ reset = "\x1b[0m"
23
+ format_str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
24
+
25
+ FORMATS = {
26
+ logging.DEBUG: grey + format_str + reset,
27
+ logging.INFO: grey + format_str + reset,
28
+ logging.WARNING: yellow + format_str + reset,
29
+ logging.ERROR: red + format_str + reset,
30
+ logging.CRITICAL: bold_red + format_str + reset,
31
+ }
32
+
33
+ def format(self, record):
34
+ log_fmt = self.FORMATS.get(record.levelno)
35
+ formatter = logging.Formatter(log_fmt)
36
+ return formatter.format(record)
37
+
38
+
39
+ class RequestContextFilter(logging.Filter):
40
+ """
41
+ Filter for adding request context to logs.
42
+ """
43
+
44
+ def __init__(self, request_id: Optional[str] = None):
45
+ super().__init__()
46
+ self.request_id = request_id
47
+
48
+
49
+ class RequestLogger:
50
+ """
51
+ Logger class for logging requests with context.
52
+ """
53
+
54
+ def __init__(self, logger_name: str, request_id: Optional[str] = None):
55
+ """
56
+ Initialize request get_global_logger().
57
+
58
+ Args:
59
+ logger_name: Logger name.
60
+ request_id: Request identifier.
61
+ """
62
+ self.logger = logging.getLogger(logger_name)
63
+ self.request_id = request_id or str(uuid.uuid4())
64
+ self.filter = RequestContextFilter(self.request_id)
65
+ get_global_logger().addFilter(self.filter)
66
+
67
+ def debug(self, msg: str, *args, **kwargs):
68
+ """Log message with DEBUG level."""
69
+ get_global_logger().debug(f"[{self.request_id}] {msg}", *args, **kwargs)
70
+
71
+ def info(self, msg: str, *args, **kwargs):
72
+ """Log message with INFO level."""
73
+ get_global_logger().info(f"[{self.request_id}] {msg}", *args, **kwargs)
74
+
75
+ def warning(self, msg: str, *args, **kwargs):
76
+ """Log message with WARNING level."""
77
+ get_global_logger().warning(f"[{self.request_id}] {msg}", *args, **kwargs)
78
+
79
+ def error(self, msg: str, *args, **kwargs):
80
+ """Log message with ERROR level."""
81
+ get_global_logger().error(f"[{self.request_id}] {msg}", *args, **kwargs)
82
+
83
+ def exception(self, msg: str, *args, **kwargs):
84
+ """Log exception with traceback."""
85
+ get_global_logger().exception(f"[{self.request_id}] {msg}", *args, **kwargs)
86
+
87
+ def critical(self, msg: str, *args, **kwargs):
88
+ """Log message with CRITICAL level."""
89
+ get_global_logger().critical(f"[{self.request_id}] {msg}", *args, **kwargs)
90
+
91
+
92
+ def setup_logging(
93
+ level: Optional[str] = None,
94
+ log_file: Optional[str] = None,
95
+ max_bytes: Optional[int] = None,
96
+ backup_count: Optional[int] = None,
97
+ rotation_type: Optional[str] = None,
98
+ rotation_when: Optional[str] = None,
99
+ rotation_interval: Optional[int] = None,
100
+ ) -> logging.Logger:
101
+ """
102
+ Configure logging for the microservice.
103
+
104
+ Args:
105
+ level: Logging level. By default, taken from configuration.
106
+ log_file: Path to log file. By default, taken from configuration.
107
+ max_bytes: Maximum log file size in bytes. By default, taken from configuration.
108
+ backup_count: Number of rotation files. By default, taken from configuration.
109
+ rotation_type: Type of log rotation ('size' or 'time'). By default, taken from configuration.
110
+ rotation_when: Time unit for rotation (D, H, M, S). By default, taken from configuration.
111
+ rotation_interval: Interval for rotation. By default, taken from configuration.
112
+
113
+ Returns:
114
+ Configured get_global_logger().
115
+ """
116
+ # Use provided parameters or defaults
117
+ level = level or "INFO"
118
+ log_file = log_file
119
+ rotation_type = rotation_type or "size"
120
+ log_dir = "./logs"
121
+ log_file_name = "mcp_proxy_adapter.log"
122
+ error_log_file = "mcp_proxy_adapter_error.log"
123
+ access_log_file = "mcp_proxy_adapter_access.log"
124
+
125
+ # Get rotation settings
126
+ max_file_size_str = "10MB"
127
+ backup_count = backup_count or 5
128
+
129
+ # Parse max file size (e.g., "10MB" -> 10 * 1024 * 1024)
130
+ max_bytes = max_bytes or _parse_file_size(max_file_size_str)
131
+
132
+ # Get format settings
133
+ log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
134
+ date_format = "%Y-%m-%d %H:%M:%S"
135
+
136
+ # Get output settings
137
+ console_output = True
138
+ file_output = True
139
+
140
+ # Convert string logging level to constant
141
+ numeric_level = getattr(logging, level.upper(), None)
142
+ if not isinstance(numeric_level, int):
143
+ numeric_level = logging.INFO
144
+
145
+ # Create root logger
146
+ logger = logging.getLogger("mcp_proxy_adapter")
147
+ logger.setLevel(numeric_level)
148
+ logger.handlers = [] # Clear handlers in case of repeated call
149
+
150
+ # Create formatter
151
+ formatter = logging.Formatter(log_format, date_format)
152
+
153
+ # Create console handler if enabled
154
+ if console_output:
155
+ console_handler = logging.StreamHandler(sys.stdout)
156
+ console_handler.setLevel(numeric_level)
157
+ console_handler.setFormatter(CustomFormatter())
158
+ logger.addHandler(console_handler)
159
+
160
+ # Create file handlers if file output is enabled
161
+ if file_output and log_dir:
162
+ # Create directory for log files if it doesn't exist
163
+ if not os.path.exists(log_dir):
164
+ os.makedirs(log_dir, exist_ok=True)
165
+
166
+ # Main log file
167
+ if log_file_name:
168
+ main_log_path = os.path.join(log_dir, log_file_name)
169
+ main_handler = RotatingFileHandler(
170
+ main_log_path,
171
+ maxBytes=max_bytes,
172
+ backupCount=backup_count,
173
+ encoding="utf-8",
174
+ )
175
+ main_handler.setLevel(numeric_level)
176
+ main_handler.setFormatter(formatter)
177
+ logger.addHandler(main_handler)
178
+
179
+ # Error log file
180
+ if error_log_file:
181
+ error_log_path = os.path.join(log_dir, error_log_file)
182
+ error_handler = RotatingFileHandler(
183
+ error_log_path,
184
+ maxBytes=max_bytes,
185
+ backupCount=backup_count,
186
+ encoding="utf-8",
187
+ )
188
+ error_handler.setLevel(logging.ERROR)
189
+ error_handler.setFormatter(formatter)
190
+ logger.addHandler(error_handler)
191
+
192
+ # Access log file (for HTTP requests)
193
+ if access_log_file:
194
+ access_log_path = os.path.join(log_dir, access_log_file)
195
+ access_handler = RotatingFileHandler(
196
+ access_log_path,
197
+ maxBytes=max_bytes,
198
+ backupCount=backup_count,
199
+ encoding="utf-8",
200
+ )
201
+ access_handler.setLevel(logging.INFO)
202
+ access_handler.setFormatter(formatter)
203
+ logger.addHandler(access_handler)
204
+
205
+ # Configure loggers for external libraries
206
+ log_levels = {}
207
+ for logger_name, logger_level in log_levels.items():
208
+ lib_logger = logging.getLogger(logger_name)
209
+ lib_logger.setLevel(getattr(logging, logger_level.upper(), logging.INFO))
210
+
211
+ return logger
212
+
213
+
214
+ def _parse_file_size(size_str) -> int:
215
+ """
216
+ Parse file size string to bytes.
217
+
218
+ Args:
219
+ size_str: Size string (e.g., "10MB", "1GB", "100KB") or int
220
+
221
+ Returns:
222
+ Size in bytes
223
+ """
224
+ # If it's already an int, return it
225
+ if isinstance(size_str, int):
226
+ return size_str
227
+
228
+ # Convert to string and parse
229
+ size_str = str(size_str).upper()
230
+ if size_str.endswith("KB"):
231
+ return int(size_str[:-2]) * 1024
232
+ elif size_str.endswith("MB"):
233
+ return int(size_str[:-2]) * 1024 * 1024
234
+ elif size_str.endswith("GB"):
235
+ return int(size_str[:-2]) * 1024 * 1024 * 1024
236
+ else:
237
+ # Assume bytes if no unit specified
238
+ return int(size_str)
239
+
240
+
241
+ # Global get_global_logger() for use throughout the application
242
+ # Initialize lazily to avoid import-time errors
243
+ logger = None
244
+
245
+ def get_global_logger():
246
+ """Get the global logger, initializing it if necessary."""
247
+ global logger
248
+ if logger is None:
249
+ logger = setup_logging()
250
+ return logger