mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__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 (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -19,54 +19,54 @@ logger = logging.getLogger(__name__)
19
19
  class ServerEngine(ABC):
20
20
  """
21
21
  Abstract base class for server engines.
22
-
22
+
23
23
  This class defines the interface that all server engines must implement,
24
24
  allowing the framework to work with different ASGI servers transparently.
25
25
  """
26
-
26
+
27
27
  @abstractmethod
28
28
  def get_name(self) -> str:
29
29
  """Get the name of the server engine."""
30
30
  pass
31
-
31
+
32
32
  @abstractmethod
33
33
  def get_supported_features(self) -> Dict[str, bool]:
34
34
  """
35
35
  Get supported features of this server engine.
36
-
36
+
37
37
  Returns:
38
38
  Dictionary mapping feature names to boolean support status
39
39
  """
40
40
  pass
41
-
41
+
42
42
  @abstractmethod
43
43
  def get_config_schema(self) -> Dict[str, Any]:
44
44
  """
45
45
  Get configuration schema for this server engine.
46
-
46
+
47
47
  Returns:
48
48
  Dictionary describing the configuration options
49
49
  """
50
50
  pass
51
-
51
+
52
52
  @abstractmethod
53
53
  def validate_config(self, config: Dict[str, Any]) -> bool:
54
54
  """
55
55
  Validate configuration for this server engine.
56
-
56
+
57
57
  Args:
58
58
  config: Configuration dictionary
59
-
59
+
60
60
  Returns:
61
61
  True if configuration is valid, False otherwise
62
62
  """
63
63
  pass
64
-
64
+
65
65
  @abstractmethod
66
66
  def run_server(self, app: Any, config: Dict[str, Any]) -> None:
67
67
  """
68
68
  Run the server with the given configuration.
69
-
69
+
70
70
  Args:
71
71
  app: ASGI application
72
72
  config: Server configuration
@@ -77,24 +77,24 @@ class ServerEngine(ABC):
77
77
  class HypercornEngine(ServerEngine):
78
78
  """
79
79
  Hypercorn server engine implementation.
80
-
80
+
81
81
  Provides full mTLS support and better SSL capabilities.
82
82
  """
83
-
83
+
84
84
  def get_name(self) -> str:
85
85
  return "hypercorn"
86
-
86
+
87
87
  def get_supported_features(self) -> Dict[str, bool]:
88
88
  return {
89
89
  "ssl_tls": True,
90
- "mtls_client_certs": True, # Full support
91
- "ssl_scope_info": True, # SSL info in request scope
90
+ "mtls_client_certs": True, # Full support
91
+ "ssl_scope_info": True, # SSL info in request scope
92
92
  "client_cert_verification": True,
93
93
  "websockets": True,
94
94
  "http2": True,
95
- "reload": True
95
+ "reload": True,
96
96
  }
97
-
97
+
98
98
  def get_config_schema(self) -> Dict[str, Any]:
99
99
  return {
100
100
  "host": {"type": "string", "default": "127.0.0.1"},
@@ -105,18 +105,18 @@ class HypercornEngine(ServerEngine):
105
105
  "ca_certs": {"type": "string", "optional": True},
106
106
  "verify_mode": {"type": "string", "optional": True},
107
107
  "reload": {"type": "boolean", "default": False},
108
- "workers": {"type": "integer", "optional": True}
108
+ "workers": {"type": "integer", "optional": True},
109
109
  }
110
-
110
+
111
111
  def validate_config(self, config: Dict[str, Any]) -> bool:
112
112
  """Validate hypercorn configuration."""
113
113
  required_fields = ["host", "port"]
114
-
114
+
115
115
  for field in required_fields:
116
116
  if field not in config:
117
117
  logger.error(f"Missing required field: {field}")
118
118
  return False
119
-
119
+
120
120
  # Validate SSL files exist if specified
121
121
  ssl_files = ["certfile", "keyfile", "ca_certs"]
122
122
  for ssl_file in ssl_files:
@@ -124,29 +124,37 @@ class HypercornEngine(ServerEngine):
124
124
  if not Path(config[ssl_file]).exists():
125
125
  logger.error(f"SSL file not found: {config[ssl_file]}")
126
126
  return False
127
-
127
+
128
128
  return True
129
-
129
+
130
130
  def run_server(self, app: Any, config: Dict[str, Any]) -> None:
131
131
  """Run hypercorn server."""
132
132
  try:
133
133
  import hypercorn.asyncio
134
134
  import asyncio
135
-
135
+
136
136
  # Prepare hypercorn config
137
137
  hypercorn_config = {
138
138
  "bind": f"{config.get('host', '127.0.0.1')}:{config.get('port', 8000)}",
139
139
  "log_level": config.get("log_level", "INFO"),
140
- "reload": config.get("reload", False)
140
+ "reload": config.get("reload", False),
141
141
  }
142
-
142
+
143
143
  # Add SSL configuration if provided
144
144
  logger.info(f"🔍 DEBUG: Input config keys: {list(config.keys())}")
145
- logger.info(f"🔍 DEBUG: Input config certfile: {config.get('certfile', 'NOT_FOUND')}")
146
- logger.info(f"🔍 DEBUG: Input config keyfile: {config.get('keyfile', 'NOT_FOUND')}")
147
- logger.info(f"🔍 DEBUG: Input config ca_certs: {config.get('ca_certs', 'NOT_FOUND')}")
148
- logger.info(f"🔍 DEBUG: Input config verify_mode: {config.get('verify_mode', 'NOT_FOUND')}")
149
-
145
+ logger.info(
146
+ f"🔍 DEBUG: Input config certfile: {config.get('certfile', 'NOT_FOUND')}"
147
+ )
148
+ logger.info(
149
+ f"🔍 DEBUG: Input config keyfile: {config.get('keyfile', 'NOT_FOUND')}"
150
+ )
151
+ logger.info(
152
+ f"🔍 DEBUG: Input config ca_certs: {config.get('ca_certs', 'NOT_FOUND')}"
153
+ )
154
+ logger.info(
155
+ f"🔍 DEBUG: Input config verify_mode: {config.get('verify_mode', 'NOT_FOUND')}"
156
+ )
157
+
150
158
  if "certfile" in config and config["certfile"]:
151
159
  hypercorn_config["certfile"] = config["certfile"]
152
160
  if "keyfile" in config and config["keyfile"]:
@@ -158,34 +166,43 @@ class HypercornEngine(ServerEngine):
158
166
  verify_mode_str = config["verify_mode"]
159
167
  if verify_mode_str == "CERT_NONE":
160
168
  import ssl
169
+
161
170
  hypercorn_config["verify_mode"] = ssl.CERT_NONE
162
171
  elif verify_mode_str == "CERT_REQUIRED":
163
172
  import ssl
173
+
164
174
  hypercorn_config["verify_mode"] = ssl.CERT_REQUIRED
165
175
  elif verify_mode_str == "CERT_OPTIONAL":
166
176
  import ssl
177
+
167
178
  hypercorn_config["verify_mode"] = ssl.CERT_OPTIONAL
168
179
  else:
169
180
  hypercorn_config["verify_mode"] = verify_mode_str
170
-
181
+
171
182
  # Add workers if specified
172
183
  if "workers" in config and config["workers"]:
173
184
  hypercorn_config["workers"] = config["workers"]
174
-
185
+
175
186
  logger.info(f"Starting hypercorn server with config: {hypercorn_config}")
176
187
  logger.info(f"SSL config from input: {config.get('ssl', 'NOT_FOUND')}")
177
- logger.info(f"Security SSL config: {config.get('security', {}).get('ssl', 'NOT_FOUND')}")
178
- logger.info(f"🔍 DEBUG: Hypercorn verify_mode: {hypercorn_config.get('verify_mode', 'NOT_SET')}")
179
- logger.info(f"🔍 DEBUG: Hypercorn ca_certs: {hypercorn_config.get('ca_certs', 'NOT_SET')}")
180
-
188
+ logger.info(
189
+ f"Security SSL config: {config.get('security', {}).get('ssl', 'NOT_FOUND')}"
190
+ )
191
+ logger.info(
192
+ f"🔍 DEBUG: Hypercorn verify_mode: {hypercorn_config.get('verify_mode', 'NOT_SET')}"
193
+ )
194
+ logger.info(
195
+ f"🔍 DEBUG: Hypercorn ca_certs: {hypercorn_config.get('ca_certs', 'NOT_SET')}"
196
+ )
197
+
181
198
  # Create config object
182
199
  config_obj = hypercorn.Config()
183
200
  for key, value in hypercorn_config.items():
184
201
  setattr(config_obj, key, value)
185
-
202
+
186
203
  # Run server
187
204
  asyncio.run(hypercorn.asyncio.serve(app, config_obj))
188
-
205
+
189
206
  except ImportError:
190
207
  logger.error("hypercorn not installed. Install with: pip install hypercorn")
191
208
  raise
@@ -197,54 +214,54 @@ class HypercornEngine(ServerEngine):
197
214
  class ServerEngineFactory:
198
215
  """
199
216
  Factory for creating server engines.
200
-
217
+
201
218
  This class manages the creation and configuration of different server engines.
202
219
  """
203
-
220
+
204
221
  _engines: Dict[str, ServerEngine] = {}
205
-
222
+
206
223
  @classmethod
207
224
  def register_engine(cls, engine: ServerEngine) -> None:
208
225
  """
209
226
  Register a server engine.
210
-
227
+
211
228
  Args:
212
229
  engine: Server engine instance to register
213
230
  """
214
231
  cls._engines[engine.get_name()] = engine
215
232
  logger.info(f"Registered server engine: {engine.get_name()}")
216
-
233
+
217
234
  @classmethod
218
235
  def get_engine(cls, name: str) -> Optional[ServerEngine]:
219
236
  """
220
237
  Get a server engine by name.
221
-
238
+
222
239
  Args:
223
240
  name: Name of the server engine
224
-
241
+
225
242
  Returns:
226
243
  Server engine instance or None if not found
227
244
  """
228
245
  return cls._engines.get(name)
229
-
246
+
230
247
  @classmethod
231
248
  def get_available_engines(cls) -> Dict[str, ServerEngine]:
232
249
  """
233
250
  Get all available server engines.
234
-
251
+
235
252
  Returns:
236
253
  Dictionary mapping engine names to engine instances
237
254
  """
238
255
  return cls._engines.copy()
239
-
256
+
240
257
  @classmethod
241
258
  def get_engine_with_feature(cls, feature: str) -> Optional[ServerEngine]:
242
259
  """
243
260
  Get the first available engine that supports a specific feature.
244
-
261
+
245
262
  Args:
246
263
  feature: Name of the feature to check
247
-
264
+
248
265
  Returns:
249
266
  Server engine that supports the feature or None
250
267
  """
@@ -252,13 +269,14 @@ class ServerEngineFactory:
252
269
  if engine.get_supported_features().get(feature, False):
253
270
  return engine
254
271
  return None
255
-
272
+
256
273
  @classmethod
257
274
  def initialize_default_engines(cls) -> None:
258
275
  """Initialize default server engines."""
259
276
  # Register hypercorn engine (only supported engine)
260
277
  try:
261
278
  import hypercorn
279
+
262
280
  cls.register_engine(HypercornEngine())
263
281
  logger.info("Hypercorn engine registered (full mTLS support available)")
264
282
  except ImportError:
@@ -12,67 +12,67 @@ class Settings:
12
12
  Settings management class for the framework.
13
13
  Provides easy access to configuration values with type conversion and validation.
14
14
  """
15
-
15
+
16
16
  # Store custom settings as a class variable
17
17
  _custom_settings: Dict[str, Any] = {}
18
-
18
+
19
19
  @classmethod
20
20
  def add_custom_settings(cls, settings: Dict[str, Any]) -> None:
21
21
  """
22
22
  Add custom settings to the settings manager.
23
-
23
+
24
24
  Args:
25
25
  settings: Dictionary with custom settings
26
26
  """
27
27
  cls._custom_settings.update(settings)
28
-
28
+
29
29
  @classmethod
30
30
  def get_custom_settings(cls) -> Dict[str, Any]:
31
31
  """
32
32
  Get all custom settings.
33
-
33
+
34
34
  Returns:
35
35
  Dictionary with all custom settings
36
36
  """
37
37
  return cls._custom_settings.copy()
38
-
38
+
39
39
  @classmethod
40
40
  def get_custom_setting_value(cls, key: str, default: Any = None) -> Any:
41
41
  """
42
42
  Get custom setting value.
43
-
43
+
44
44
  Args:
45
45
  key: Setting key
46
46
  default: Default value if key not found
47
-
47
+
48
48
  Returns:
49
49
  Setting value
50
50
  """
51
51
  return cls._custom_settings.get(key, default)
52
-
52
+
53
53
  @classmethod
54
54
  def set_custom_setting_value(cls, key: str, value: Any) -> None:
55
55
  """
56
56
  Set custom setting value.
57
-
57
+
58
58
  Args:
59
59
  key: Setting key
60
60
  value: Value to set
61
61
  """
62
62
  cls._custom_settings[key] = value
63
-
63
+
64
64
  @classmethod
65
65
  def clear_custom_settings(cls) -> None:
66
66
  """
67
67
  Clear all custom settings.
68
68
  """
69
69
  cls._custom_settings.clear()
70
-
70
+
71
71
  @staticmethod
72
72
  def get_server_settings() -> Dict[str, Any]:
73
73
  """
74
74
  Get server configuration settings.
75
-
75
+
76
76
  Returns:
77
77
  Dictionary with server settings
78
78
  """
@@ -80,14 +80,14 @@ class Settings:
80
80
  "host": config.get("server.host", "0.0.0.0"),
81
81
  "port": config.get("server.port", 8000),
82
82
  "debug": config.get("server.debug", False),
83
- "log_level": config.get("server.log_level", "INFO")
83
+ "log_level": config.get("server.log_level", "INFO"),
84
84
  }
85
-
85
+
86
86
  @staticmethod
87
87
  def get_logging_settings() -> Dict[str, Any]:
88
88
  """
89
89
  Get logging configuration settings.
90
-
90
+
91
91
  Returns:
92
92
  Dictionary with logging settings
93
93
  """
@@ -96,68 +96,76 @@ class Settings:
96
96
  "file": config.get("logging.file"),
97
97
  "log_dir": config.get("logging.log_dir", "./logs"),
98
98
  "log_file": config.get("logging.log_file", "mcp_proxy_adapter.log"),
99
- "error_log_file": config.get("logging.error_log_file", "mcp_proxy_adapter_error.log"),
100
- "access_log_file": config.get("logging.access_log_file", "mcp_proxy_adapter_access.log"),
99
+ "error_log_file": config.get(
100
+ "logging.error_log_file", "mcp_proxy_adapter_error.log"
101
+ ),
102
+ "access_log_file": config.get(
103
+ "logging.access_log_file", "mcp_proxy_adapter_access.log"
104
+ ),
101
105
  "max_file_size": config.get("logging.max_file_size", "10MB"),
102
106
  "backup_count": config.get("logging.backup_count", 5),
103
- "format": config.get("logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"),
107
+ "format": config.get(
108
+ "logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
109
+ ),
104
110
  "date_format": config.get("logging.date_format", "%Y-%m-%d %H:%M:%S"),
105
111
  "console_output": config.get("logging.console_output", True),
106
- "file_output": config.get("logging.file_output", True)
112
+ "file_output": config.get("logging.file_output", True),
107
113
  }
108
-
114
+
109
115
  @staticmethod
110
116
  def get_commands_settings() -> Dict[str, Any]:
111
117
  """
112
118
  Get commands configuration settings.
113
-
119
+
114
120
  Returns:
115
121
  Dictionary with commands settings
116
122
  """
117
123
  return {
118
124
  "auto_discovery": config.get("commands.auto_discovery", True),
119
- "discovery_path": config.get("commands.discovery_path", "mcp_proxy_adapter.commands"),
125
+ "discovery_path": config.get(
126
+ "commands.discovery_path", "mcp_proxy_adapter.commands"
127
+ ),
120
128
  "auto_commands_path": config.get("commands.auto_commands_path"),
121
- "custom_commands_path": config.get("commands.custom_commands_path")
129
+ "custom_commands_path": config.get("commands.custom_commands_path"),
122
130
  }
123
-
131
+
124
132
  @staticmethod
125
133
  def get_custom_setting(key: str, default: Any = None) -> Any:
126
134
  """
127
135
  Get custom setting from configuration.
128
-
136
+
129
137
  Args:
130
138
  key: Configuration key in dot notation (e.g., "custom.feature_enabled")
131
139
  default: Default value if key not found
132
-
140
+
133
141
  Returns:
134
142
  Configuration value
135
143
  """
136
144
  return config.get(key, default)
137
-
145
+
138
146
  @staticmethod
139
147
  def get_all_settings() -> Dict[str, Any]:
140
148
  """
141
149
  Get all configuration settings including custom settings.
142
-
150
+
143
151
  Returns:
144
152
  Dictionary with all configuration settings
145
153
  """
146
154
  all_settings = config.get_all()
147
- all_settings['custom_settings'] = Settings._custom_settings
155
+ all_settings["custom_settings"] = Settings._custom_settings
148
156
  return all_settings
149
-
157
+
150
158
  @staticmethod
151
159
  def set_custom_setting(key: str, value: Any) -> None:
152
160
  """
153
161
  Set custom setting in configuration.
154
-
162
+
155
163
  Args:
156
164
  key: Configuration key in dot notation
157
165
  value: Value to set
158
166
  """
159
167
  config.set(key, value)
160
-
168
+
161
169
  @staticmethod
162
170
  def reload_config() -> None:
163
171
  """
@@ -170,22 +178,22 @@ class ServerSettings:
170
178
  """
171
179
  Server-specific settings helper.
172
180
  """
173
-
181
+
174
182
  @staticmethod
175
183
  def get_host() -> str:
176
184
  """Get server host."""
177
185
  return config.get("server.host", "0.0.0.0")
178
-
186
+
179
187
  @staticmethod
180
188
  def get_port() -> int:
181
189
  """Get server port."""
182
190
  return config.get("server.port", 8000)
183
-
191
+
184
192
  @staticmethod
185
193
  def get_debug() -> bool:
186
194
  """Get debug mode."""
187
195
  return config.get("server.debug", False)
188
-
196
+
189
197
  @staticmethod
190
198
  def get_log_level() -> str:
191
199
  """Get log level."""
@@ -196,57 +204,59 @@ class LoggingSettings:
196
204
  """
197
205
  Logging-specific settings helper.
198
206
  """
199
-
207
+
200
208
  @staticmethod
201
209
  def get_level() -> str:
202
210
  """Get logging level."""
203
211
  return config.get("logging.level", "INFO")
204
-
212
+
205
213
  @staticmethod
206
214
  def get_log_dir() -> str:
207
215
  """Get log directory."""
208
216
  return config.get("logging.log_dir", "./logs")
209
-
217
+
210
218
  @staticmethod
211
219
  def get_log_file() -> Optional[str]:
212
220
  """Get main log file name."""
213
221
  return config.get("logging.log_file", "mcp_proxy_adapter.log")
214
-
222
+
215
223
  @staticmethod
216
224
  def get_error_log_file() -> Optional[str]:
217
225
  """Get error log file name."""
218
226
  return config.get("logging.error_log_file", "mcp_proxy_adapter_error.log")
219
-
227
+
220
228
  @staticmethod
221
229
  def get_access_log_file() -> Optional[str]:
222
230
  """Get access log file name."""
223
231
  return config.get("logging.access_log_file", "mcp_proxy_adapter_access.log")
224
-
232
+
225
233
  @staticmethod
226
234
  def get_max_file_size() -> str:
227
235
  """Get max file size."""
228
236
  return config.get("logging.max_file_size", "10MB")
229
-
237
+
230
238
  @staticmethod
231
239
  def get_backup_count() -> int:
232
240
  """Get backup count."""
233
241
  return config.get("logging.backup_count", 5)
234
-
242
+
235
243
  @staticmethod
236
244
  def get_format() -> str:
237
245
  """Get log format."""
238
- return config.get("logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s")
239
-
246
+ return config.get(
247
+ "logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
248
+ )
249
+
240
250
  @staticmethod
241
251
  def get_date_format() -> str:
242
252
  """Get date format."""
243
253
  return config.get("logging.date_format", "%Y-%m-%d %H:%M:%S")
244
-
254
+
245
255
  @staticmethod
246
256
  def get_console_output() -> bool:
247
257
  """Get console output setting."""
248
258
  return config.get("logging.console_output", True)
249
-
259
+
250
260
  @staticmethod
251
261
  def get_file_output() -> bool:
252
262
  """Get file output setting."""
@@ -257,17 +267,17 @@ class CommandsSettings:
257
267
  """
258
268
  Commands-specific settings helper.
259
269
  """
260
-
270
+
261
271
  @staticmethod
262
272
  def get_auto_discovery() -> bool:
263
273
  """Get auto discovery setting."""
264
274
  return config.get("commands.auto_discovery", True)
265
-
275
+
266
276
  @staticmethod
267
277
  def get_discovery_path() -> str:
268
278
  """Get discovery path."""
269
279
  return config.get("commands.discovery_path", "mcp_proxy_adapter.commands")
270
-
280
+
271
281
  @staticmethod
272
282
  def get_custom_commands_path() -> Optional[str]:
273
283
  """Get custom commands path."""
@@ -328,7 +338,7 @@ def reload_settings() -> None:
328
338
  def add_custom_settings(settings: Dict[str, Any]) -> None:
329
339
  """
330
340
  Add custom settings to the settings manager.
331
-
341
+
332
342
  Args:
333
343
  settings: Dictionary with custom settings
334
344
  """
@@ -338,7 +348,7 @@ def add_custom_settings(settings: Dict[str, Any]) -> None:
338
348
  def get_custom_settings() -> Dict[str, Any]:
339
349
  """
340
350
  Get all custom settings.
341
-
351
+
342
352
  Returns:
343
353
  Dictionary with all custom settings
344
354
  """
@@ -348,11 +358,11 @@ def get_custom_settings() -> Dict[str, Any]:
348
358
  def get_custom_setting_value(key: str, default: Any = None) -> Any:
349
359
  """
350
360
  Get custom setting value.
351
-
361
+
352
362
  Args:
353
363
  key: Setting key
354
364
  default: Default value if key not found
355
-
365
+
356
366
  Returns:
357
367
  Setting value
358
368
  """
@@ -362,7 +372,7 @@ def get_custom_setting_value(key: str, default: Any = None) -> Any:
362
372
  def set_custom_setting_value(key: str, value: Any) -> None:
363
373
  """
364
374
  Set custom setting value.
365
-
375
+
366
376
  Args:
367
377
  key: Setting key
368
378
  value: Value to set
@@ -374,4 +384,4 @@ def clear_custom_settings() -> None:
374
384
  """
375
385
  Clear all custom settings.
376
386
  """
377
- Settings.clear_custom_settings()
387
+ Settings.clear_custom_settings()