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
@@ -14,8 +14,12 @@ from pathlib import Path
14
14
  try:
15
15
  from mcp_security_framework import SecurityManager, SecurityConfig
16
16
  from mcp_security_framework.schemas.config import (
17
- AuthConfig, SSLConfig, PermissionConfig, RateLimitConfig
17
+ AuthConfig,
18
+ SSLConfig,
19
+ PermissionConfig,
20
+ RateLimitConfig,
18
21
  )
22
+
19
23
  # Note: SecurityRequest and SecurityResult are not available in current version
20
24
  SECURITY_FRAMEWORK_AVAILABLE = True
21
25
  except ImportError:
@@ -34,88 +38,88 @@ from mcp_proxy_adapter.core.logging import logger
34
38
  class SecurityAdapter:
35
39
  """
36
40
  Adapter for integrating with mcp_security_framework.
37
-
41
+
38
42
  Provides methods to convert mcp_proxy_adapter configuration to SecurityConfig
39
43
  and handle request validation through the security framework.
40
44
  """
41
-
45
+
42
46
  def __init__(self, config: Dict[str, Any]):
43
47
  """
44
48
  Initialize security adapter.
45
-
49
+
46
50
  Args:
47
51
  config: mcp_proxy_adapter configuration dictionary
48
52
  """
49
53
  self.config = config
50
54
  self.security_manager = None
51
-
55
+
52
56
  if SECURITY_FRAMEWORK_AVAILABLE:
53
57
  self.security_manager = self._create_security_manager()
54
58
  logger.info("Security adapter initialized with mcp_security_framework")
55
59
  else:
56
60
  logger.warning("mcp_security_framework not available, using fallback mode")
57
-
61
+
58
62
  def _create_security_manager(self) -> Optional[SecurityManager]:
59
63
  """
60
64
  Create SecurityManager from mcp_proxy_adapter configuration.
61
-
65
+
62
66
  Returns:
63
67
  SecurityManager instance or None if framework not available
64
68
  """
65
69
  if not SECURITY_FRAMEWORK_AVAILABLE:
66
70
  return None
67
-
71
+
68
72
  try:
69
73
  security_config = self._convert_config()
70
74
  return SecurityManager(security_config)
71
75
  except Exception as e:
72
76
  logger.error(f"Failed to create SecurityManager: {e}")
73
77
  return None
74
-
78
+
75
79
  def _convert_config(self) -> SecurityConfig:
76
80
  """
77
81
  Convert mcp_proxy_adapter configuration to SecurityConfig.
78
-
82
+
79
83
  Returns:
80
84
  SecurityConfig instance
81
85
  """
82
86
  # Get security configuration section
83
87
  security_config = self.config.get("security", {})
84
-
88
+
85
89
  # Convert auth configuration
86
90
  auth_config = self._convert_auth_config(security_config)
87
-
91
+
88
92
  # Convert SSL configuration
89
93
  ssl_config = self._convert_ssl_config(security_config)
90
-
94
+
91
95
  # Convert permissions configuration
92
96
  permission_config = self._convert_permission_config(security_config)
93
-
97
+
94
98
  # Convert rate limit configuration
95
99
  rate_limit_config = self._convert_rate_limit_config(security_config)
96
-
100
+
97
101
  return SecurityConfig(
98
102
  auth=auth_config,
99
103
  ssl=ssl_config,
100
104
  permissions=permission_config,
101
- rate_limit=rate_limit_config
105
+ rate_limit=rate_limit_config,
102
106
  )
103
-
107
+
104
108
  def _convert_auth_config(self, security_config: Dict[str, Any]) -> AuthConfig:
105
109
  """
106
110
  Convert authentication configuration.
107
-
111
+
108
112
  Args:
109
113
  security_config: Security configuration section
110
-
114
+
111
115
  Returns:
112
116
  AuthConfig instance
113
117
  """
114
118
  auth_config = security_config.get("auth", {})
115
-
119
+
116
120
  # Get authentication methods
117
121
  methods = auth_config.get("methods", ["api_key"])
118
-
122
+
119
123
  # Get API keys from legacy config if not in security section
120
124
  api_keys = auth_config.get("api_keys", {})
121
125
  if not api_keys:
@@ -123,31 +127,31 @@ class SecurityAdapter:
123
127
  legacy_ssl = self.config.get("ssl", {})
124
128
  if "api_keys" in legacy_ssl:
125
129
  api_keys = legacy_ssl["api_keys"]
126
-
130
+
127
131
  return AuthConfig(
128
132
  enabled=auth_config.get("enabled", True),
129
133
  methods=methods,
130
134
  api_keys=api_keys,
131
135
  jwt_secret=auth_config.get("jwt_secret", ""),
132
- jwt_algorithm=auth_config.get("jwt_algorithm", "HS256")
136
+ jwt_algorithm=auth_config.get("jwt_algorithm", "HS256"),
133
137
  )
134
-
138
+
135
139
  def _convert_ssl_config(self, security_config: Dict[str, Any]) -> SSLConfig:
136
140
  """
137
141
  Convert SSL configuration.
138
-
142
+
139
143
  Args:
140
144
  security_config: Security configuration section
141
-
145
+
142
146
  Returns:
143
147
  SSLConfig instance
144
148
  """
145
149
  ssl_config = security_config.get("ssl", {})
146
-
150
+
147
151
  # Fallback to legacy SSL config if not in security section
148
152
  if not ssl_config:
149
153
  ssl_config = self.config.get("ssl", {})
150
-
154
+
151
155
  return SSLConfig(
152
156
  enabled=ssl_config.get("enabled", False),
153
157
  cert_file=ssl_config.get("cert_file"),
@@ -155,65 +159,69 @@ class SecurityAdapter:
155
159
  ca_cert=ssl_config.get("ca_cert"),
156
160
  min_tls_version=ssl_config.get("min_tls_version", "TLSv1.2"),
157
161
  verify_client=ssl_config.get("verify_client", False),
158
- client_cert_required=ssl_config.get("client_cert_required", False)
162
+ client_cert_required=ssl_config.get("client_cert_required", False),
159
163
  )
160
-
161
- def _convert_permission_config(self, security_config: Dict[str, Any]) -> PermissionConfig:
164
+
165
+ def _convert_permission_config(
166
+ self, security_config: Dict[str, Any]
167
+ ) -> PermissionConfig:
162
168
  """
163
169
  Convert permissions configuration.
164
-
170
+
165
171
  Args:
166
172
  security_config: Security configuration section
167
-
173
+
168
174
  Returns:
169
175
  PermissionConfig instance
170
176
  """
171
177
  permission_config = security_config.get("permissions", {})
172
-
178
+
173
179
  # Fallback to legacy roles config if not in security section
174
180
  if not permission_config:
175
181
  roles_config = self.config.get("roles", {})
176
182
  permission_config = {
177
183
  "enabled": roles_config.get("enabled", True),
178
184
  "roles_file": roles_config.get("config_file", "roles.json"),
179
- "default_role": "user"
185
+ "default_role": "user",
180
186
  }
181
-
187
+
182
188
  return PermissionConfig(
183
189
  enabled=permission_config.get("enabled", True),
184
190
  roles_file=permission_config.get("roles_file", "roles.json"),
185
191
  default_role=permission_config.get("default_role", "user"),
186
- deny_by_default=permission_config.get("deny_by_default", True)
192
+ deny_by_default=permission_config.get("deny_by_default", True),
187
193
  )
188
-
189
- def _convert_rate_limit_config(self, security_config: Dict[str, Any]) -> RateLimitConfig:
194
+
195
+ def _convert_rate_limit_config(
196
+ self, security_config: Dict[str, Any]
197
+ ) -> RateLimitConfig:
190
198
  """
191
199
  Convert rate limit configuration.
192
-
200
+
193
201
  Args:
194
202
  security_config: Security configuration section
195
-
203
+
196
204
  Returns:
197
205
  RateLimitConfig instance
198
206
  """
199
207
  rate_limit_config = security_config.get("rate_limit", {})
200
-
208
+
201
209
  return RateLimitConfig(
202
210
  enabled=rate_limit_config.get("enabled", True),
203
211
  requests_per_minute=rate_limit_config.get("requests_per_minute", 60),
204
212
  requests_per_hour=rate_limit_config.get("requests_per_hour", 1000),
205
213
  burst_limit=rate_limit_config.get("burst_limit", 10),
206
214
  by_ip=rate_limit_config.get("by_ip", True),
207
- by_user=rate_limit_config.get("by_user", True)
215
+ by_user=rate_limit_config.get("by_user", True),
208
216
  )
209
-
217
+
210
218
  def validate_request(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
211
219
  """
212
220
  Validate request through mcp_security_framework.
213
-
221
+
214
222
  Args:
215
223
  request_data: Request data dictionary
216
-
224
+
217
225
  Returns:
218
226
  Validation result dictionary
219
227
  """
@@ -222,16 +230,16 @@ class SecurityAdapter:
222
230
  # Fallback validation when framework is not available
223
231
  logger.debug("Using fallback validation")
224
232
  return self._fallback_validation(request_data)
225
-
233
+
226
234
  try:
227
235
  # Convert request data to SecurityRequest
228
236
  security_request = self._create_security_request(request_data)
229
-
237
+
230
238
  # Validate through security framework
231
239
  result = self.security_manager.validate_request(security_request)
232
-
240
+
233
241
  return result.to_dict()
234
-
242
+
235
243
  except Exception as e:
236
244
  logger.error(f"Security validation failed: {e}")
237
245
  return {
@@ -239,16 +247,16 @@ class SecurityAdapter:
239
247
  "error_code": -32603,
240
248
  "error_message": f"Security validation error: {str(e)}",
241
249
  "roles": [],
242
- "user_id": None
250
+ "user_id": None,
243
251
  }
244
-
252
+
245
253
  def _create_security_request(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
246
254
  """
247
255
  Create request data for security validation.
248
-
256
+
249
257
  Args:
250
258
  request_data: Request data dictionary
251
-
259
+
252
260
  Returns:
253
261
  Request data dictionary for security validation
254
262
  """
@@ -258,16 +266,16 @@ class SecurityAdapter:
258
266
  "headers": request_data.get("headers", {}),
259
267
  "query_params": request_data.get("query_params", {}),
260
268
  "client_ip": request_data.get("client_ip", "unknown"),
261
- "body": request_data.get("body", {})
269
+ "body": request_data.get("body", {}),
262
270
  }
263
-
271
+
264
272
  def _fallback_validation(self, request_data: Dict[str, Any]) -> Dict[str, Any]:
265
273
  """
266
274
  Fallback validation when mcp_security_framework is not available.
267
-
275
+
268
276
  Args:
269
277
  request_data: Request data dictionary
270
-
278
+
271
279
  Returns:
272
280
  Validation result dictionary
273
281
  """
@@ -275,32 +283,32 @@ class SecurityAdapter:
275
283
  headers = request_data.get("headers", {})
276
284
  query_params = request_data.get("query_params", {})
277
285
  body = request_data.get("body", {})
278
-
286
+
279
287
  # Check for API key in headers (FastAPI converts headers to lowercase)
280
288
  api_key = headers.get("x-api-key") or headers.get("X-API-Key")
281
289
  logger.debug(f"API key from headers: {api_key}")
282
-
290
+
283
291
  # Check for API key in query parameters
284
292
  if not api_key:
285
293
  api_key = query_params.get("api_key")
286
294
  logger.debug(f"API key from query params: {api_key}")
287
-
295
+
288
296
  # Check for API key in JSON-RPC body
289
297
  if not api_key and isinstance(body, dict):
290
298
  api_key = body.get("params", {}).get("api_key")
291
299
  logger.debug(f"API key from body: {api_key}")
292
-
300
+
293
301
  # Get API keys from config
294
302
  api_keys = self._get_api_keys()
295
303
  logger.debug(f"Available API keys: {list(api_keys.keys())}")
296
-
304
+
297
305
  if api_key and api_key in api_keys:
298
306
  return {
299
307
  "is_valid": True,
300
308
  "error_code": None,
301
309
  "error_message": None,
302
310
  "roles": ["user"],
303
- "user_id": api_keys[api_key]
311
+ "user_id": api_keys[api_key],
304
312
  }
305
313
  else:
306
314
  return {
@@ -308,13 +316,13 @@ class SecurityAdapter:
308
316
  "error_code": -32000,
309
317
  "error_message": "API key not provided or invalid",
310
318
  "roles": [],
311
- "user_id": None
319
+ "user_id": None,
312
320
  }
313
-
321
+
314
322
  def _get_api_keys(self) -> Dict[str, str]:
315
323
  """
316
324
  Get API keys from configuration.
317
-
325
+
318
326
  Returns:
319
327
  Dictionary mapping API keys to usernames
320
328
  """
@@ -322,48 +330,51 @@ class SecurityAdapter:
322
330
  security_config = self.config.get("security", {})
323
331
  auth_config = security_config.get("auth", {})
324
332
  api_keys = auth_config.get("api_keys", {})
325
-
333
+
326
334
  logger.debug(f"Security config: {security_config}")
327
335
  logger.debug(f"Auth config: {auth_config}")
328
336
  logger.debug(f"API keys from security config: {api_keys}")
329
-
337
+
330
338
  # Fallback to legacy SSL config
331
339
  if not api_keys:
332
340
  ssl_config = self.config.get("ssl", {})
333
341
  api_keys = ssl_config.get("api_keys", {})
334
342
  logger.debug(f"API keys from SSL config: {api_keys}")
335
-
343
+
336
344
  logger.info(f"Total API keys loaded: {len(api_keys)}")
337
345
  return api_keys
338
-
346
+
339
347
  def create_middleware(self, framework: str = "fastapi"):
340
348
  """
341
349
  Create framework-specific middleware.
342
-
350
+
343
351
  Args:
344
352
  framework: Framework type (fastapi, flask, etc.)
345
-
353
+
346
354
  Returns:
347
355
  Middleware instance
348
356
  """
349
357
  if not self.security_manager:
350
358
  logger.warning("Cannot create middleware: security framework not available")
351
359
  return None
352
-
360
+
353
361
  try:
354
362
  if framework == "fastapi":
355
- from mcp_security_framework.middleware import create_fastapi_security_middleware
363
+ from mcp_security_framework.middleware import (
364
+ create_fastapi_security_middleware,
365
+ )
366
+
356
367
  return create_fastapi_security_middleware(self.security_manager)
357
368
  else:
358
369
  raise ValueError(f"Unsupported framework: {framework}")
359
370
  except Exception as e:
360
371
  logger.error(f"Failed to create middleware: {e}")
361
372
  return None
362
-
373
+
363
374
  def is_available(self) -> bool:
364
375
  """
365
376
  Check if security framework is available.
366
-
377
+
367
378
  Returns:
368
379
  True if framework is available, False otherwise
369
380
  """
@@ -15,19 +15,19 @@ from .security_adapter import SecurityAdapter
15
15
  class SecurityFactory:
16
16
  """
17
17
  Factory for creating security components.
18
-
18
+
19
19
  Provides static methods to create security adapters, managers,
20
20
  and middleware components with proper configuration handling.
21
21
  """
22
-
22
+
23
23
  @staticmethod
24
24
  def create_security_adapter(config: Dict[str, Any]) -> SecurityAdapter:
25
25
  """
26
26
  Create SecurityAdapter from configuration.
27
-
27
+
28
28
  Args:
29
29
  config: mcp_proxy_adapter configuration dictionary
30
-
30
+
31
31
  Returns:
32
32
  SecurityAdapter instance
33
33
  """
@@ -38,15 +38,15 @@ class SecurityFactory:
38
38
  except Exception as e:
39
39
  logger.error(f"Failed to create security adapter: {e}")
40
40
  raise
41
-
41
+
42
42
  @staticmethod
43
43
  def create_security_manager(config: Dict[str, Any]):
44
44
  """
45
45
  Create SecurityManager from configuration.
46
-
46
+
47
47
  Args:
48
48
  config: mcp_proxy_adapter configuration dictionary
49
-
49
+
50
50
  Returns:
51
51
  SecurityManager instance or None if not available
52
52
  """
@@ -56,103 +56,103 @@ class SecurityFactory:
56
56
  except Exception as e:
57
57
  logger.error(f"Failed to create security manager: {e}")
58
58
  return None
59
-
59
+
60
60
  @staticmethod
61
61
  def create_middleware(config: Dict[str, Any], framework: str = "fastapi"):
62
62
  """
63
63
  Create framework-specific security middleware.
64
-
64
+
65
65
  Args:
66
66
  config: mcp_proxy_adapter configuration dictionary
67
67
  framework: Framework type (fastapi, flask, etc.)
68
-
68
+
69
69
  Returns:
70
70
  Middleware instance or None if creation failed
71
71
  """
72
72
  try:
73
73
  adapter = SecurityFactory.create_security_adapter(config)
74
74
  middleware = adapter.create_middleware(framework)
75
-
75
+
76
76
  if middleware:
77
77
  logger.info(f"Security middleware created for {framework}")
78
78
  else:
79
79
  logger.warning(f"Failed to create security middleware for {framework}")
80
-
80
+
81
81
  return middleware
82
-
82
+
83
83
  except Exception as e:
84
84
  logger.error(f"Failed to create security middleware: {e}")
85
85
  return None
86
-
86
+
87
87
  @staticmethod
88
88
  def create_fastapi_middleware(config: Dict[str, Any]):
89
89
  """
90
90
  Create FastAPI-specific security middleware.
91
-
91
+
92
92
  Args:
93
93
  config: mcp_proxy_adapter configuration dictionary
94
-
94
+
95
95
  Returns:
96
96
  FastAPI middleware instance or None if creation failed
97
97
  """
98
98
  return SecurityFactory.create_middleware(config, "fastapi")
99
-
99
+
100
100
  @staticmethod
101
101
  def validate_config(config: Dict[str, Any]) -> bool:
102
102
  """
103
103
  Validate security configuration.
104
-
104
+
105
105
  Args:
106
106
  config: Configuration dictionary to validate
107
-
107
+
108
108
  Returns:
109
109
  True if configuration is valid, False otherwise
110
110
  """
111
111
  try:
112
112
  # Check if security section exists
113
113
  security_config = config.get("security", {})
114
-
114
+
115
115
  # Validate required fields
116
116
  if not isinstance(security_config, dict):
117
117
  logger.error("Security configuration must be a dictionary")
118
118
  return False
119
-
119
+
120
120
  # Validate auth configuration
121
121
  auth_config = security_config.get("auth", {})
122
122
  if not isinstance(auth_config, dict):
123
123
  logger.error("Auth configuration must be a dictionary")
124
124
  return False
125
-
125
+
126
126
  # Validate SSL configuration
127
127
  ssl_config = security_config.get("ssl", {})
128
128
  if not isinstance(ssl_config, dict):
129
129
  logger.error("SSL configuration must be a dictionary")
130
130
  return False
131
-
131
+
132
132
  # Validate permissions configuration
133
133
  permissions_config = security_config.get("permissions", {})
134
134
  if not isinstance(permissions_config, dict):
135
135
  logger.error("Permissions configuration must be a dictionary")
136
136
  return False
137
-
137
+
138
138
  # Validate rate limit configuration
139
139
  rate_limit_config = security_config.get("rate_limit", {})
140
140
  if not isinstance(rate_limit_config, dict):
141
141
  logger.error("Rate limit configuration must be a dictionary")
142
142
  return False
143
-
143
+
144
144
  logger.info("Security configuration validation passed")
145
145
  return True
146
-
146
+
147
147
  except Exception as e:
148
148
  logger.error(f"Configuration validation failed: {e}")
149
149
  return False
150
-
150
+
151
151
  @staticmethod
152
152
  def get_default_config() -> Dict[str, Any]:
153
153
  """
154
154
  Get default security configuration.
155
-
155
+
156
156
  Returns:
157
157
  Default security configuration dictionary
158
158
  """
@@ -165,7 +165,7 @@ class SecurityFactory:
165
165
  "methods": ["api_key"],
166
166
  "api_keys": {},
167
167
  "jwt_secret": "",
168
- "jwt_algorithm": "HS256"
168
+ "jwt_algorithm": "HS256",
169
169
  },
170
170
  "ssl": {
171
171
  "enabled": False,
@@ -174,13 +174,13 @@ class SecurityFactory:
174
174
  "ca_cert": None,
175
175
  "min_tls_version": "TLSv1.2",
176
176
  "verify_client": False,
177
- "client_cert_required": False
177
+ "client_cert_required": False,
178
178
  },
179
179
  "permissions": {
180
180
  "enabled": True,
181
181
  "roles_file": "roles.json",
182
182
  "default_role": "user",
183
- "deny_by_default": True
183
+ "deny_by_default": True,
184
184
  },
185
185
  "rate_limit": {
186
186
  "enabled": True,
@@ -188,52 +188,58 @@ class SecurityFactory:
188
188
  "requests_per_hour": 1000,
189
189
  "burst_limit": 10,
190
190
  "by_ip": True,
191
- "by_user": True
192
- }
191
+ "by_user": True,
192
+ },
193
193
  }
194
194
  }
195
-
195
+
196
196
  @staticmethod
197
- def merge_config(base_config: Dict[str, Any], security_config: Dict[str, Any]) -> Dict[str, Any]:
197
+ def merge_config(
198
+ base_config: Dict[str, Any], security_config: Dict[str, Any]
199
+ ) -> Dict[str, Any]:
198
200
  """
199
201
  Merge security configuration into base configuration.
200
-
202
+
201
203
  Args:
202
204
  base_config: Base configuration dictionary
203
205
  security_config: Security configuration to merge
204
-
206
+
205
207
  Returns:
206
208
  Merged configuration dictionary
207
209
  """
208
210
  try:
209
211
  # Create a copy of base config
210
212
  merged_config = base_config.copy()
211
-
213
+
212
214
  # Merge security configuration
213
215
  if "security" not in merged_config:
214
216
  merged_config["security"] = {}
215
-
217
+
216
218
  # Deep merge security configuration
217
219
  SecurityFactory._deep_merge(merged_config["security"], security_config)
218
-
220
+
219
221
  logger.info("Security configuration merged successfully")
220
222
  return merged_config
221
-
223
+
222
224
  except Exception as e:
223
225
  logger.error(f"Failed to merge security configuration: {e}")
224
226
  return base_config
225
-
227
+
226
228
  @staticmethod
227
229
  def _deep_merge(base_dict: Dict[str, Any], update_dict: Dict[str, Any]) -> None:
228
230
  """
229
231
  Deep merge two dictionaries.
230
-
232
+
231
233
  Args:
232
234
  base_dict: Base dictionary to update
233
235
  update_dict: Dictionary with updates
234
236
  """
235
237
  for key, value in update_dict.items():
236
- if key in base_dict and isinstance(base_dict[key], dict) and isinstance(value, dict):
238
+ if (
239
+ key in base_dict
240
+ and isinstance(base_dict[key], dict)
241
+ and isinstance(value, dict)
242
+ ):
237
243
  SecurityFactory._deep_merge(base_dict[key], value)
238
244
  else:
239
245
  base_dict[key] = value