mcp-proxy-adapter 6.2.35__py3-none-any.whl → 6.3.0__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.
@@ -8,24 +8,33 @@ Author: Vasiliy Zdanovskiy
8
8
  email: vasilyvz@gmail.com
9
9
  """
10
10
 
11
- import logging
12
- from typing import Dict, Any, Optional, List
13
- from pathlib import Path
11
+ from typing import Dict, Any, List
14
12
 
15
13
  # Direct imports from framework
16
14
  try:
17
15
  from mcp_security_framework import (
18
- SecurityManager, AuthManager, CertificateManager,
19
- PermissionManager, RateLimiter
16
+ SecurityManager,
17
+ AuthManager,
18
+ CertificateManager,
19
+ PermissionManager,
20
+ RateLimiter,
20
21
  )
21
22
  from mcp_security_framework.schemas.config import (
22
- SecurityConfig, AuthConfig, SSLConfig, PermissionConfig,
23
- RateLimitConfig, CertificateConfig, LoggingConfig
23
+ SecurityConfig,
24
+ AuthConfig,
25
+ SSLConfig,
26
+ PermissionConfig,
27
+ RateLimitConfig,
28
+ CertificateConfig,
29
+ LoggingConfig,
24
30
  )
25
31
  from mcp_security_framework.schemas.models import (
26
- AuthResult, ValidationResult, CertificateInfo, CertificatePair
32
+ AuthResult,
33
+ ValidationResult,
34
+ CertificatePair,
27
35
  )
28
36
  from mcp_security_framework.middleware.fastapi_middleware import FastAPISecurityMiddleware
37
+
29
38
  SECURITY_FRAMEWORK_AVAILABLE = True
30
39
  except ImportError:
31
40
  SECURITY_FRAMEWORK_AVAILABLE = False
@@ -43,38 +52,38 @@ from mcp_proxy_adapter.core.logging import logger
43
52
  class SecurityIntegration:
44
53
  """
45
54
  Direct integration with mcp_security_framework.
46
-
55
+
47
56
  This class replaces all project security methods with direct calls
48
57
  to the security framework components.
49
58
  """
50
-
59
+
51
60
  def __init__(self, config: Dict[str, Any]):
52
61
  """
53
62
  Initialize security integration.
54
-
63
+
55
64
  Args:
56
65
  config: Configuration dictionary
57
66
  """
58
67
  if not SECURITY_FRAMEWORK_AVAILABLE:
59
68
  raise ImportError("mcp_security_framework is not available")
60
-
69
+
61
70
  self.config = config
62
71
  self.security_config = self._create_security_config()
63
-
72
+
64
73
  # Initialize framework components
65
74
  self.security_manager = SecurityManager(self.security_config)
66
75
  self.permission_manager = PermissionManager(self.security_config.permissions)
67
76
  self.auth_manager = AuthManager(self.security_config.auth, self.permission_manager)
68
77
  self.certificate_manager = CertificateManager(self.security_config.certificates)
69
78
  self.rate_limiter = RateLimiter(self.security_config.rate_limit)
70
-
79
+
71
80
  logger.info("Security integration initialized with mcp_security_framework")
72
-
81
+
73
82
  def _create_security_config(self) -> SecurityConfig:
74
83
  """Create SecurityConfig from project configuration."""
75
84
  # self.config is already the security section passed from unified_security.py
76
85
  security_section = self.config
77
-
86
+
78
87
  # Create SSL config
79
88
  ssl_config = SSLConfig(
80
89
  enabled=security_section.get("ssl", {}).get("enabled", False),
@@ -87,9 +96,9 @@ class SecurityIntegration:
87
96
  min_tls_version=security_section.get("ssl", {}).get("min_tls_version", "TLSv1.2"),
88
97
  check_hostname=security_section.get("ssl", {}).get("check_hostname", True),
89
98
  check_expiry=security_section.get("ssl", {}).get("check_expiry", True),
90
- expiry_warning_days=security_section.get("ssl", {}).get("expiry_warning_days", 30)
99
+ expiry_warning_days=security_section.get("ssl", {}).get("expiry_warning_days", 30),
91
100
  )
92
-
101
+
93
102
  # Create auth config
94
103
  auth_config = AuthConfig(
95
104
  enabled=security_section.get("auth", {}).get("enabled", True),
@@ -100,21 +109,23 @@ class SecurityIntegration:
100
109
  jwt_algorithm=security_section.get("auth", {}).get("jwt_algorithm", "HS256"),
101
110
  jwt_expiry_hours=security_section.get("auth", {}).get("jwt_expiry_hours", 24),
102
111
  certificate_auth=security_section.get("auth", {}).get("certificate_auth", False),
103
- public_paths=security_section.get("auth", {}).get("public_paths", [])
112
+ public_paths=security_section.get("auth", {}).get("public_paths", []),
104
113
  )
105
-
114
+
106
115
  # Create permission config - handle null values properly
107
116
  permissions_section = security_section.get("permissions", {})
108
117
  permissions_enabled = permissions_section.get("enabled", True)
109
-
118
+
110
119
  if permissions_enabled:
111
120
  roles_file = permissions_section.get("roles_file")
112
121
 
113
122
  # If roles_file is None or empty string, don't pass it to avoid framework errors
114
123
  if roles_file is None or roles_file == "":
115
- logger.warning("roles_file is None or empty, permissions will use default configuration")
124
+ logger.warning(
125
+ "roles_file is None or empty, permissions will use default configuration"
126
+ )
116
127
  roles_file = None
117
-
128
+
118
129
  permission_config = PermissionConfig(
119
130
  enabled=True,
120
131
  roles_file=roles_file,
@@ -125,7 +136,7 @@ class SecurityIntegration:
125
136
  permission_cache_ttl=permissions_section.get("permission_cache_ttl", 300),
126
137
  wildcard_permissions=permissions_section.get("wildcard_permissions", False),
127
138
  strict_mode=permissions_section.get("strict_mode", True),
128
- roles=permissions_section.get("roles")
139
+ roles=permissions_section.get("roles"),
129
140
  )
130
141
  else:
131
142
  # Create minimal permission config when permissions are disabled
@@ -139,42 +150,56 @@ class SecurityIntegration:
139
150
  permission_cache_ttl=300,
140
151
  wildcard_permissions=False,
141
152
  strict_mode=False,
142
- roles={}
153
+ roles={},
143
154
  )
144
-
155
+
145
156
  # Create rate limit config
146
157
  rate_limit_config = RateLimitConfig(
147
158
  enabled=security_section.get("rate_limit", {}).get("enabled", True),
148
- default_requests_per_minute=security_section.get("rate_limit", {}).get("default_requests_per_minute", 60),
149
- default_requests_per_hour=security_section.get("rate_limit", {}).get("default_requests_per_hour", 1000),
159
+ default_requests_per_minute=security_section.get("rate_limit", {}).get(
160
+ "default_requests_per_minute", 60
161
+ ),
162
+ default_requests_per_hour=security_section.get("rate_limit", {}).get(
163
+ "default_requests_per_hour", 1000
164
+ ),
150
165
  burst_limit=security_section.get("rate_limit", {}).get("burst_limit", 2),
151
- window_size_seconds=security_section.get("rate_limit", {}).get("window_size_seconds", 60),
166
+ window_size_seconds=security_section.get("rate_limit", {}).get(
167
+ "window_size_seconds", 60
168
+ ),
152
169
  storage_backend=security_section.get("rate_limit", {}).get("storage_backend", "memory"),
153
170
  exempt_paths=security_section.get("rate_limit", {}).get("exempt_paths", []),
154
- exempt_roles=security_section.get("rate_limit", {}).get("exempt_roles", [])
171
+ exempt_roles=security_section.get("rate_limit", {}).get("exempt_roles", []),
155
172
  )
156
-
173
+
157
174
  # Create certificate config
158
175
  certificate_config = CertificateConfig(
159
176
  enabled=security_section.get("certificates", {}).get("enabled", False),
160
177
  ca_cert_path=security_section.get("certificates", {}).get("ca_cert_path"),
161
178
  ca_key_path=security_section.get("certificates", {}).get("ca_key_path"),
162
- cert_storage_path=security_section.get("certificates", {}).get("cert_storage_path", "./certs"),
163
- key_storage_path=security_section.get("certificates", {}).get("key_storage_path", "./keys"),
164
- default_validity_days=security_section.get("certificates", {}).get("default_validity_days", 365),
179
+ cert_storage_path=security_section.get("certificates", {}).get(
180
+ "cert_storage_path", "./certs"
181
+ ),
182
+ key_storage_path=security_section.get("certificates", {}).get(
183
+ "key_storage_path", "./keys"
184
+ ),
185
+ default_validity_days=security_section.get("certificates", {}).get(
186
+ "default_validity_days", 365
187
+ ),
165
188
  key_size=security_section.get("certificates", {}).get("key_size", 2048),
166
- hash_algorithm=security_section.get("certificates", {}).get("hash_algorithm", "sha256")
189
+ hash_algorithm=security_section.get("certificates", {}).get("hash_algorithm", "sha256"),
167
190
  )
168
-
191
+
169
192
  # Create logging config
170
193
  logging_config = LoggingConfig(
171
194
  enabled=security_section.get("logging", {}).get("enabled", True),
172
195
  level=security_section.get("logging", {}).get("level", "INFO"),
173
- format=security_section.get("logging", {}).get("format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"),
196
+ format=security_section.get("logging", {}).get(
197
+ "format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
198
+ ),
174
199
  console_output=security_section.get("logging", {}).get("console_output", True),
175
- file_path=security_section.get("logging", {}).get("file_path")
200
+ file_path=security_section.get("logging", {}).get("file_path"),
176
201
  )
177
-
202
+
178
203
  # Create main security config
179
204
  return SecurityConfig(
180
205
  ssl=ssl_config,
@@ -185,95 +210,134 @@ class SecurityIntegration:
185
210
  logging=logging_config,
186
211
  debug=security_section.get("debug", False),
187
212
  environment=security_section.get("environment", "dev"),
188
- version=security_section.get("version", "1.0.0")
213
+ version=security_section.get("version", "1.0.0"),
189
214
  )
190
-
215
+
191
216
  # Authentication methods - direct calls to AuthManager
192
217
  async def authenticate_api_key(self, api_key: str) -> AuthResult:
193
218
  """Authenticate using API key."""
194
219
  return await self.auth_manager.authenticate_api_key(api_key)
195
-
220
+
196
221
  async def authenticate_jwt(self, token: str) -> AuthResult:
197
222
  """Authenticate using JWT token."""
198
223
  return await self.auth_manager.authenticate_jwt(token)
199
-
224
+
200
225
  async def authenticate_certificate(self, cert_data: bytes) -> AuthResult:
201
226
  """Authenticate using certificate."""
202
227
  return await self.auth_manager.authenticate_certificate(cert_data)
203
-
228
+
204
229
  async def validate_request(self, request_data: Dict[str, Any]) -> ValidationResult:
205
230
  """Validate request using security manager."""
206
231
  return await self.security_manager.validate_request(request_data)
207
-
232
+
208
233
  # Certificate methods - direct calls to CertificateManager
209
234
  async def create_ca_certificate(self, common_name: str, **kwargs) -> CertificatePair:
210
235
  """Create CA certificate."""
211
236
  return await self.certificate_manager.create_ca_certificate(common_name, **kwargs)
212
-
237
+
213
238
  async def create_client_certificate(self, common_name: str, **kwargs) -> CertificatePair:
214
239
  """Create client certificate."""
215
240
  return await self.certificate_manager.create_client_certificate(common_name, **kwargs)
216
-
241
+
217
242
  async def create_server_certificate(self, common_name: str, **kwargs) -> CertificatePair:
218
243
  """Create server certificate."""
219
244
  return await self.certificate_manager.create_server_certificate(common_name, **kwargs)
220
-
245
+
221
246
  async def validate_certificate(self, cert_path: str) -> bool:
222
- """Validate certificate."""
223
- return await self.certificate_manager.validate_certificate(cert_path)
224
-
247
+ """Validate certificate with CRL check if enabled."""
248
+ try:
249
+ # Get CRL configuration from security config
250
+ crl_config = None
251
+ if hasattr(self.security_config, "certificates"):
252
+ cert_config = self.security_config.certificates
253
+ # Only analyze CRL paths if certificates are enabled
254
+ if (
255
+ hasattr(cert_config, "enabled")
256
+ and cert_config.enabled
257
+ and hasattr(cert_config, "crl_enabled")
258
+ and cert_config.crl_enabled
259
+ ):
260
+ crl_config = {
261
+ "crl_enabled": cert_config.crl_enabled,
262
+ "crl_path": getattr(cert_config, "crl_path", None),
263
+ "crl_url": getattr(cert_config, "crl_url", None),
264
+ "crl_validity_days": getattr(cert_config, "crl_validity_days", 30),
265
+ }
266
+
267
+ # Use mcp_security_framework's validate_certificate_chain with CRL
268
+ if crl_config and crl_config.get("crl_enabled"):
269
+ from mcp_security_framework.utils.cert_utils import validate_certificate_chain
270
+ from .crl_utils import CRLManager
271
+
272
+ # Get CRL data
273
+ crl_manager = CRLManager(crl_config)
274
+ crl_data = crl_manager.get_crl_data()
275
+
276
+ # Validate with CRL
277
+ if crl_data:
278
+ return validate_certificate_chain(
279
+ cert_path, self.security_config.certificates.ca_cert_path, crl_data
280
+ )
281
+
282
+ # Fallback to standard validation
283
+ return await self.certificate_manager.validate_certificate(cert_path)
284
+
285
+ except Exception as e:
286
+ logger.error(f"Certificate validation failed: {e}")
287
+ return False
288
+
225
289
  async def extract_roles_from_certificate(self, cert_path: str) -> List[str]:
226
290
  """Extract roles from certificate."""
227
291
  return await self.certificate_manager.extract_roles_from_certificate(cert_path)
228
-
292
+
229
293
  async def revoke_certificate(self, cert_path: str) -> bool:
230
294
  """Revoke certificate."""
231
295
  return await self.certificate_manager.revoke_certificate(cert_path)
232
-
296
+
233
297
  # Permission methods - direct calls to PermissionManager
234
298
  async def check_permission(self, user_id: str, permission: str) -> bool:
235
299
  """Check user permission."""
236
300
  return await self.permission_manager.check_permission(user_id, permission)
237
-
301
+
238
302
  async def get_user_roles(self, user_id: str) -> List[str]:
239
303
  """Get user roles."""
240
304
  return await self.permission_manager.get_user_roles(user_id)
241
-
305
+
242
306
  async def add_user_role(self, user_id: str, role: str) -> bool:
243
307
  """Add role to user."""
244
308
  return await self.permission_manager.add_user_role(user_id, role)
245
-
309
+
246
310
  async def remove_user_role(self, user_id: str, role: str) -> bool:
247
311
  """Remove role from user."""
248
312
  return await self.permission_manager.remove_user_role(user_id, role)
249
-
313
+
250
314
  # Rate limiting methods - direct calls to RateLimiter
251
315
  async def check_rate_limit(self, identifier: str, limit_type: str = "per_minute") -> bool:
252
316
  """Check rate limit."""
253
317
  return await self.rate_limiter.check_rate_limit(identifier, limit_type)
254
-
318
+
255
319
  async def increment_rate_limit(self, identifier: str) -> None:
256
320
  """Increment rate limit counter."""
257
321
  await self.rate_limiter.increment_rate_limit(identifier)
258
-
322
+
259
323
  async def get_rate_limit_info(self, identifier: str) -> Dict[str, Any]:
260
324
  """Get rate limit information."""
261
325
  return await self.rate_limiter.get_rate_limit_info(identifier)
262
-
326
+
263
327
  # Middleware creation - direct use of framework middleware
264
328
  def create_fastapi_middleware(self, app) -> FastAPISecurityMiddleware:
265
329
  """Create FastAPI security middleware."""
266
330
  return FastAPISecurityMiddleware(app, self.security_config)
267
-
331
+
268
332
  # Utility methods
269
333
  def is_security_enabled(self) -> bool:
270
334
  """Check if security is enabled."""
271
335
  return self.security_config.auth.enabled or self.security_config.ssl.enabled
272
-
336
+
273
337
  def get_public_paths(self) -> List[str]:
274
338
  """Get public paths that bypass authentication."""
275
339
  return self.security_config.auth.public_paths
276
-
340
+
277
341
  def get_security_config(self) -> SecurityConfig:
278
342
  """Get security configuration."""
279
343
  return self.security_config
@@ -283,13 +347,13 @@ class SecurityIntegration:
283
347
  def create_security_integration(config: Dict[str, Any]) -> SecurityIntegration:
284
348
  """
285
349
  Create security integration instance.
286
-
350
+
287
351
  Args:
288
352
  config: Configuration dictionary
289
-
353
+
290
354
  Returns:
291
355
  SecurityIntegration instance
292
-
356
+
293
357
  Raises:
294
358
  RuntimeError: If security integration cannot be created
295
359
  """
@@ -3,8 +3,10 @@ SSL Utilities Module
3
3
 
4
4
  This module provides utilities for SSL/TLS configuration and certificate validation.
5
5
  Integrates with AuthValidator from Phase 0 for certificate validation.
6
+ Supports CRL (Certificate Revocation List) validation.
6
7
 
7
- Author: MCP Proxy Adapter Team
8
+ Author: Vasiliy Zdanovskiy
9
+ email: vasilyvz@gmail.com
8
10
  Version: 1.0.0
9
11
  """
10
12
 
@@ -14,6 +16,7 @@ from typing import List, Optional, Dict, Any
14
16
  from pathlib import Path
15
17
 
16
18
  from .auth_validator import AuthValidator
19
+ from .crl_utils import CRLManager
17
20
 
18
21
  logger = logging.getLogger(__name__)
19
22
 
@@ -47,7 +50,8 @@ class SSLUtils:
47
50
  verify_client: bool = False,
48
51
  cipher_suites: Optional[List[str]] = None,
49
52
  min_tls_version: str = "1.2",
50
- max_tls_version: str = "1.3") -> ssl.SSLContext:
53
+ max_tls_version: str = "1.3",
54
+ crl_config: Optional[Dict[str, Any]] = None) -> ssl.SSLContext:
51
55
  """
52
56
  Create SSL context with specified configuration.
53
57
 
@@ -59,6 +63,7 @@ class SSLUtils:
59
63
  cipher_suites: List of cipher suites to use
60
64
  min_tls_version: Minimum TLS version
61
65
  max_tls_version: Maximum TLS version
66
+ crl_config: CRL configuration dictionary (optional)
62
67
 
63
68
  Returns:
64
69
  Configured SSL context
@@ -73,6 +78,17 @@ class SSLUtils:
73
78
  if not result.is_valid:
74
79
  raise ValueError(f"Invalid certificate: {result.error_message}")
75
80
 
81
+ # Check CRL if configured
82
+ if crl_config:
83
+ try:
84
+ crl_manager = CRLManager(crl_config)
85
+ if crl_manager.is_certificate_revoked(cert_file):
86
+ raise ValueError(f"Certificate is revoked according to CRL: {cert_file}")
87
+ except Exception as e:
88
+ logger.error(f"CRL check failed: {e}")
89
+ # For security, fail if CRL check fails
90
+ raise ValueError(f"CRL validation failed: {e}")
91
+
76
92
  # Check if files exist
77
93
  if not Path(cert_file).exists():
78
94
  raise FileNotFoundError(f"Certificate file not found: {cert_file}")
@@ -111,12 +127,13 @@ class SSLUtils:
111
127
  return context
112
128
 
113
129
  @staticmethod
114
- def validate_certificate(cert_file: str) -> bool:
130
+ def validate_certificate(cert_file: str, crl_config: Optional[Dict[str, Any]] = None) -> bool:
115
131
  """
116
- Validate certificate using AuthValidator.
132
+ Validate certificate using AuthValidator and optional CRL check.
117
133
 
118
134
  Args:
119
135
  cert_file: Path to certificate file
136
+ crl_config: CRL configuration dictionary (optional)
120
137
 
121
138
  Returns:
122
139
  True if certificate is valid, False otherwise
@@ -124,7 +141,22 @@ class SSLUtils:
124
141
  try:
125
142
  validator = AuthValidator()
126
143
  result = validator.validate_certificate(cert_file)
127
- return result.is_valid
144
+ if not result.is_valid:
145
+ return False
146
+
147
+ # Check CRL if configured
148
+ if crl_config:
149
+ try:
150
+ crl_manager = CRLManager(crl_config)
151
+ if crl_manager.is_certificate_revoked(cert_file):
152
+ logger.warning(f"Certificate is revoked according to CRL: {cert_file}")
153
+ return False
154
+ except Exception as e:
155
+ logger.error(f"CRL check failed: {e}")
156
+ # For security, consider certificate invalid if CRL check fails
157
+ return False
158
+
159
+ return True
128
160
  except Exception as e:
129
161
  logger.error(f"Certificate validation failed: {e}")
130
162
  return False
@@ -107,6 +107,7 @@ class ConfigGenerator:
107
107
  "hash_algorithm": "sha256",
108
108
  "crl_enabled": False,
109
109
  "crl_path": None,
110
+ "crl_url": None,
110
111
  "crl_validity_days": 30,
111
112
  "auto_renewal": False,
112
113
  "renewal_threshold_days": 30
mcp_proxy_adapter/main.py CHANGED
@@ -19,6 +19,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
19
19
 
20
20
  from mcp_proxy_adapter.api.app import create_app
21
21
  from mcp_proxy_adapter.config import Config
22
+ from mcp_proxy_adapter.core.config_validator import ConfigValidator
22
23
 
23
24
 
24
25
  def main():
@@ -27,28 +28,36 @@ def main():
27
28
  parser = argparse.ArgumentParser(description="MCP Proxy Adapter Server")
28
29
  parser.add_argument("--config", "-c", type=str, help="Path to configuration file")
29
30
  args = parser.parse_args()
30
-
31
+
31
32
  # Load configuration
32
33
  if args.config:
33
34
  config = Config(config_path=args.config)
34
35
  else:
35
36
  config = Config()
36
37
 
38
+ # Validate UUID configuration (mandatory)
39
+ validator = ConfigValidator(config.get_all())
40
+ if not validator.validate_all():
41
+ print("❌ Configuration validation failed:")
42
+ for error in validator.get_errors():
43
+ print(f" - {error}")
44
+ sys.exit(1)
45
+ print("✅ Configuration validation passed")
37
46
 
38
47
  # Create application
39
48
  app = create_app(app_config=config)
40
-
49
+
41
50
  # Get server configuration
42
51
  host = config.get("server.host", "0.0.0.0")
43
52
  port = config.get("server.port", 8000)
44
-
53
+
45
54
  # Get SSL configuration
46
55
  ssl_enabled = config.get("ssl.enabled", False)
47
56
  ssl_cert_file = config.get("ssl.cert_file")
48
57
  ssl_key_file = config.get("ssl.key_file")
49
58
  ssl_ca_cert = config.get("ssl.ca_cert")
50
59
  verify_client = config.get("ssl.verify_client", False)
51
-
60
+
52
61
  print(f"🚀 Starting MCP Proxy Adapter")
53
62
  print(f"🌐 Server: {host}:{port}")
54
63
  if ssl_enabled:
@@ -59,18 +68,18 @@ def main():
59
68
  print(f" CA: {ssl_ca_cert}")
60
69
  print(f" Client verification: {verify_client}")
61
70
  print("=" * 50)
62
-
71
+
63
72
  # Configure hypercorn
64
73
  config_hypercorn = hypercorn.config.Config()
65
74
  config_hypercorn.bind = [f"{host}:{port}"]
66
-
75
+
67
76
  if ssl_enabled and ssl_cert_file and ssl_key_file:
68
77
  config_hypercorn.certfile = ssl_cert_file
69
78
  config_hypercorn.keyfile = ssl_key_file
70
-
79
+
71
80
  if ssl_ca_cert:
72
81
  config_hypercorn.ca_certs = ssl_ca_cert
73
-
82
+
74
83
  if verify_client:
75
84
  # For mTLS, require client certificates
76
85
  config_hypercorn.set_cert_reqs(ssl.CERT_REQUIRED)
@@ -80,11 +89,11 @@ def main():
80
89
  # For regular HTTPS without client verification
81
90
  config_hypercorn.set_cert_reqs(ssl.CERT_NONE)
82
91
  config_hypercorn.verify_mode = ssl.CERT_NONE
83
-
92
+
84
93
  print(f"🔐 Starting HTTPS server with hypercorn...")
85
94
  else:
86
95
  print(f"🌐 Starting HTTP server with hypercorn...")
87
-
96
+
88
97
  # Run the server
89
98
  asyncio.run(hypercorn.asyncio.serve(app, config_hypercorn))
90
99
 
@@ -107,6 +107,7 @@ class ConfigGenerator:
107
107
  "hash_algorithm": "sha256",
108
108
  "crl_enabled": False,
109
109
  "crl_path": None,
110
+ "crl_url": None,
110
111
  "crl_validity_days": 30,
111
112
  "auto_renewal": False,
112
113
  "renewal_threshold_days": 30
@@ -2,5 +2,5 @@
2
2
  Version information for MCP Proxy Adapter.
3
3
  """
4
4
 
5
- __version__ = "6.2.35"
5
+ __version__ = "6.3.0"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.2.35
3
+ Version: 6.3.0
4
4
  Summary: Powerful JSON-RPC microservices framework with built-in security, authentication, and proxy registration
5
5
  Home-page: https://github.com/maverikod/mcp-proxy-adapter
6
6
  Author: Vasiliy Zdanovskiy