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
@@ -25,15 +25,15 @@ class SSLUtils:
25
25
  """
26
26
  SSL utilities for creating SSL contexts and validating certificates.
27
27
  """
28
-
28
+
29
29
  # TLS version mapping
30
30
  TLS_VERSIONS = {
31
31
  "1.0": ssl.TLSVersion.TLSv1,
32
32
  "1.1": ssl.TLSVersion.TLSv1_1,
33
33
  "1.2": ssl.TLSVersion.TLSv1_2,
34
- "1.3": ssl.TLSVersion.TLSv1_3
34
+ "1.3": ssl.TLSVersion.TLSv1_3,
35
35
  }
36
-
36
+
37
37
  # Cipher suite mapping
38
38
  CIPHER_SUITES = {
39
39
  "TLS_AES_256_GCM_SHA384": "TLS_AES_256_GCM_SHA384",
@@ -41,20 +41,23 @@ class SSLUtils:
41
41
  "TLS_AES_128_GCM_SHA256": "TLS_AES_128_GCM_SHA256",
42
42
  "ECDHE-RSA-AES256-GCM-SHA384": "ECDHE-RSA-AES256-GCM-SHA384",
43
43
  "ECDHE-RSA-AES128-GCM-SHA256": "ECDHE-RSA-AES128-GCM-SHA256",
44
- "ECDHE-RSA-CHACHA20-POLY1305": "ECDHE-RSA-CHACHA20-POLY1305"
44
+ "ECDHE-RSA-CHACHA20-POLY1305": "ECDHE-RSA-CHACHA20-POLY1305",
45
45
  }
46
-
46
+
47
47
  @staticmethod
48
- def create_ssl_context(cert_file: str, key_file: str,
49
- ca_cert: Optional[str] = None,
50
- verify_client: bool = False,
51
- cipher_suites: Optional[List[str]] = None,
52
- min_tls_version: str = "1.2",
53
- max_tls_version: str = "1.3",
54
- crl_config: Optional[Dict[str, Any]] = None) -> ssl.SSLContext:
48
+ def create_ssl_context(
49
+ cert_file: str,
50
+ key_file: str,
51
+ ca_cert: Optional[str] = None,
52
+ verify_client: bool = False,
53
+ cipher_suites: Optional[List[str]] = None,
54
+ min_tls_version: str = "1.2",
55
+ max_tls_version: str = "1.3",
56
+ crl_config: Optional[Dict[str, Any]] = None,
57
+ ) -> ssl.SSLContext:
55
58
  """
56
59
  Create SSL context with specified configuration.
57
-
60
+
58
61
  Args:
59
62
  cert_file: Path to certificate file
60
63
  key_file: Path to private key file
@@ -64,10 +67,10 @@ class SSLUtils:
64
67
  min_tls_version: Minimum TLS version
65
68
  max_tls_version: Maximum TLS version
66
69
  crl_config: CRL configuration dictionary (optional)
67
-
70
+
68
71
  Returns:
69
72
  Configured SSL context
70
-
73
+
71
74
  Raises:
72
75
  ValueError: If certificate validation fails
73
76
  FileNotFoundError: If certificate or key files not found
@@ -77,18 +80,20 @@ class SSLUtils:
77
80
  result = validator.validate_certificate(cert_file)
78
81
  if not result.is_valid:
79
82
  raise ValueError(f"Invalid certificate: {result.error_message}")
80
-
83
+
81
84
  # Check CRL if configured
82
85
  if crl_config:
83
86
  try:
84
87
  crl_manager = CRLManager(crl_config)
85
88
  if crl_manager.is_certificate_revoked(cert_file):
86
- raise ValueError(f"Certificate is revoked according to CRL: {cert_file}")
89
+ raise ValueError(
90
+ f"Certificate is revoked according to CRL: {cert_file}"
91
+ )
87
92
  except Exception as e:
88
93
  logger.error(f"CRL check failed: {e}")
89
94
  # For security, fail if CRL check fails
90
95
  raise ValueError(f"CRL validation failed: {e}")
91
-
96
+
92
97
  # Check if files exist
93
98
  if not Path(cert_file).exists():
94
99
  raise FileNotFoundError(f"Certificate file not found: {cert_file}")
@@ -96,45 +101,47 @@ class SSLUtils:
96
101
  raise FileNotFoundError(f"Key file not found: {key_file}")
97
102
  if ca_cert and not Path(ca_cert).exists():
98
103
  raise FileNotFoundError(f"CA certificate file not found: {ca_cert}")
99
-
104
+
100
105
  # Create SSL context
101
106
  if verify_client:
102
107
  context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
103
108
  else:
104
109
  context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
105
-
110
+
106
111
  # Load certificate and key
107
112
  context.load_cert_chain(cert_file, key_file)
108
-
113
+
109
114
  # Load CA certificate if provided
110
115
  if ca_cert:
111
116
  context.load_verify_locations(ca_cert)
112
-
117
+
113
118
  # Configure client verification
114
119
  if verify_client:
115
120
  context.verify_mode = ssl.CERT_REQUIRED
116
121
  context.check_hostname = False
117
122
  else:
118
123
  context.verify_mode = ssl.CERT_NONE
119
-
124
+
120
125
  # Setup cipher suites
121
126
  SSLUtils.setup_cipher_suites(context, cipher_suites or [])
122
-
127
+
123
128
  # Setup TLS versions
124
129
  SSLUtils.setup_tls_versions(context, min_tls_version, max_tls_version)
125
-
130
+
126
131
  logger.info(f"SSL context created successfully with cert: {cert_file}")
127
132
  return context
128
-
133
+
129
134
  @staticmethod
130
- def validate_certificate(cert_file: str, crl_config: Optional[Dict[str, Any]] = None) -> bool:
135
+ def validate_certificate(
136
+ cert_file: str, crl_config: Optional[Dict[str, Any]] = None
137
+ ) -> bool:
131
138
  """
132
139
  Validate certificate using AuthValidator and optional CRL check.
133
-
140
+
134
141
  Args:
135
142
  cert_file: Path to certificate file
136
143
  crl_config: CRL configuration dictionary (optional)
137
-
144
+
138
145
  Returns:
139
146
  True if certificate is valid, False otherwise
140
147
  """
@@ -143,36 +150,38 @@ class SSLUtils:
143
150
  result = validator.validate_certificate(cert_file)
144
151
  if not result.is_valid:
145
152
  return False
146
-
153
+
147
154
  # Check CRL if configured
148
155
  if crl_config:
149
156
  try:
150
157
  crl_manager = CRLManager(crl_config)
151
158
  if crl_manager.is_certificate_revoked(cert_file):
152
- logger.warning(f"Certificate is revoked according to CRL: {cert_file}")
159
+ logger.warning(
160
+ f"Certificate is revoked according to CRL: {cert_file}"
161
+ )
153
162
  return False
154
163
  except Exception as e:
155
164
  logger.error(f"CRL check failed: {e}")
156
165
  # For security, consider certificate invalid if CRL check fails
157
166
  return False
158
-
167
+
159
168
  return True
160
169
  except Exception as e:
161
170
  logger.error(f"Certificate validation failed: {e}")
162
171
  return False
163
-
172
+
164
173
  @staticmethod
165
174
  def setup_cipher_suites(context: ssl.SSLContext, cipher_suites: List[str]) -> None:
166
175
  """
167
176
  Setup cipher suites for SSL context.
168
-
177
+
169
178
  Args:
170
179
  context: SSL context to configure
171
180
  cipher_suites: List of cipher suite names
172
181
  """
173
182
  if not cipher_suites:
174
183
  return
175
-
184
+
176
185
  # Convert cipher suite names to actual cipher suite strings
177
186
  actual_ciphers = []
178
187
  for cipher_name in cipher_suites:
@@ -180,19 +189,21 @@ class SSLUtils:
180
189
  actual_ciphers.append(SSLUtils.CIPHER_SUITES[cipher_name])
181
190
  else:
182
191
  logger.warning(f"Unknown cipher suite: {cipher_name}")
183
-
192
+
184
193
  if actual_ciphers:
185
194
  try:
186
195
  context.set_ciphers(":".join(actual_ciphers))
187
196
  logger.info(f"Cipher suites configured: {actual_ciphers}")
188
197
  except ssl.SSLError as e:
189
198
  logger.error(f"Failed to set cipher suites: {e}")
190
-
199
+
191
200
  @staticmethod
192
- def setup_tls_versions(context: ssl.SSLContext, min_version: str, max_version: str) -> None:
201
+ def setup_tls_versions(
202
+ context: ssl.SSLContext, min_version: str, max_version: str
203
+ ) -> None:
193
204
  """
194
205
  Setup TLS version range for SSL context.
195
-
206
+
196
207
  Args:
197
208
  context: SSL context to configure
198
209
  min_version: Minimum TLS version
@@ -201,66 +212,68 @@ class SSLUtils:
201
212
  try:
202
213
  min_tls = SSLUtils.TLS_VERSIONS.get(min_version)
203
214
  max_tls = SSLUtils.TLS_VERSIONS.get(max_version)
204
-
215
+
205
216
  if min_tls and max_tls:
206
217
  context.minimum_version = min_tls
207
218
  context.maximum_version = max_tls
208
219
  logger.info(f"TLS versions configured: {min_version} - {max_version}")
209
220
  else:
210
- logger.warning(f"Invalid TLS version range: {min_version} - {max_version}")
221
+ logger.warning(
222
+ f"Invalid TLS version range: {min_version} - {max_version}"
223
+ )
211
224
  except Exception as e:
212
225
  logger.error(f"Failed to set TLS versions: {e}")
213
-
226
+
214
227
  @staticmethod
215
228
  def check_tls_version(min_version: str, max_version: str) -> bool:
216
229
  """
217
230
  Check if TLS version range is valid.
218
-
231
+
219
232
  Args:
220
233
  min_version: Minimum TLS version
221
234
  max_version: Maximum TLS version
222
-
235
+
223
236
  Returns:
224
237
  True if version range is valid, False otherwise
225
238
  """
226
239
  min_tls = SSLUtils.TLS_VERSIONS.get(min_version)
227
240
  max_tls = SSLUtils.TLS_VERSIONS.get(max_version)
228
-
241
+
229
242
  if not min_tls or not max_tls:
230
243
  return False
231
-
244
+
232
245
  # Check if min version is less than or equal to max version
233
246
  return min_tls <= max_tls
234
-
247
+
235
248
  @staticmethod
236
249
  def get_ssl_config_for_hypercorn(ssl_config: Dict[str, Any]) -> Dict[str, Any]:
237
250
  """
238
251
  Get SSL configuration for hypercorn from transport configuration.
239
-
252
+
240
253
  Args:
241
254
  ssl_config: SSL configuration from transport manager
242
-
255
+
243
256
  Returns:
244
257
  Configuration for hypercorn
245
258
  """
246
259
  hypercorn_ssl = {}
247
-
260
+
248
261
  if not ssl_config:
249
262
  return hypercorn_ssl
250
-
263
+
251
264
  # Basic SSL parameters
252
265
  if ssl_config.get("cert_file"):
253
266
  hypercorn_ssl["certfile"] = ssl_config["cert_file"]
254
-
267
+
255
268
  if ssl_config.get("key_file"):
256
269
  hypercorn_ssl["keyfile"] = ssl_config["key_file"]
257
-
270
+
258
271
  if ssl_config.get("ca_cert"):
259
272
  hypercorn_ssl["ca_certs"] = ssl_config["ca_cert"]
260
-
273
+
261
274
  # Client verification mode
262
275
  if ssl_config.get("verify_client", False):
263
276
  hypercorn_ssl["verify_mode"] = "CERT_REQUIRED"
264
-
277
+
265
278
  logger.info(f"Generated hypercorn SSL config: {hypercorn_ssl}")
266
- return hypercorn_ssl
279
+ return hypercorn_ssl
@@ -14,6 +14,7 @@ from mcp_proxy_adapter.core.logging import logger
14
14
 
15
15
  class TransportType(Enum):
16
16
  """Transport types enumeration."""
17
+
17
18
  HTTP = "http"
18
19
  HTTPS = "https"
19
20
  MTLS = "mtls"
@@ -22,6 +23,7 @@ class TransportType(Enum):
22
23
  @dataclass
23
24
  class TransportConfig:
24
25
  """Transport configuration data class."""
26
+
25
27
  type: TransportType
26
28
  port: Optional[int]
27
29
  ssl_enabled: bool
@@ -35,36 +37,36 @@ class TransportConfig:
35
37
  class TransportManager:
36
38
  """
37
39
  Transport manager for handling different transport types.
38
-
40
+
39
41
  This class manages transport configuration and provides utilities
40
42
  for determining ports and SSL settings based on transport type.
41
43
  """
42
-
44
+
43
45
  # Default ports for transport types
44
46
  DEFAULT_PORTS = {
45
47
  TransportType.HTTP: 8000,
46
48
  TransportType.HTTPS: 8443,
47
- TransportType.MTLS: 9443
49
+ TransportType.MTLS: 9443,
48
50
  }
49
-
51
+
50
52
  def __init__(self):
51
53
  """Initialize transport manager."""
52
54
  self._config: Optional[TransportConfig] = None
53
55
  self._current_transport: Optional[TransportType] = None
54
-
56
+
55
57
  def load_config(self, config: Dict[str, Any]) -> bool:
56
58
  """
57
59
  Load transport configuration from config dict.
58
-
60
+
59
61
  Args:
60
62
  config: Configuration dictionary
61
-
63
+
62
64
  Returns:
63
65
  True if config loaded successfully, False otherwise
64
66
  """
65
67
  try:
66
68
  transport_config = config.get("transport", {})
67
-
69
+
68
70
  # Get transport type
69
71
  transport_type_str = transport_config.get("type", "http").lower()
70
72
  try:
@@ -72,24 +74,29 @@ class TransportManager:
72
74
  except ValueError:
73
75
  logger.error(f"Invalid transport type: {transport_type_str}")
74
76
  return False
75
-
77
+
76
78
  # Get port (use default if not specified)
77
79
  port = transport_config.get("port")
78
80
  if port is None:
79
81
  port = self.DEFAULT_PORTS.get(transport_type, 8000)
80
-
82
+
81
83
  # Get SSL configuration
82
84
  ssl_config = transport_config.get("ssl", {})
83
85
  ssl_enabled = ssl_config.get("enabled", False)
84
-
86
+
85
87
  # Validate SSL requirements
86
- if transport_type in [TransportType.HTTPS, TransportType.MTLS] and not ssl_enabled:
87
- logger.error(f"SSL must be enabled for transport type: {transport_type.value}")
88
+ if (
89
+ transport_type in [TransportType.HTTPS, TransportType.MTLS]
90
+ and not ssl_enabled
91
+ ):
92
+ logger.error(
93
+ f"SSL must be enabled for transport type: {transport_type.value}"
94
+ )
88
95
  return False
89
-
96
+
90
97
  if transport_type == TransportType.HTTP and ssl_enabled:
91
98
  logger.warning("SSL enabled for HTTP transport - this may cause issues")
92
-
99
+
93
100
  # Create transport config
94
101
  self._config = TransportConfig(
95
102
  type=transport_type,
@@ -99,100 +106,102 @@ class TransportManager:
99
106
  key_file=ssl_config.get("key_file") if ssl_enabled else None,
100
107
  ca_cert=ssl_config.get("ca_cert") if ssl_enabled else None,
101
108
  verify_client=ssl_config.get("verify_client", False),
102
- client_cert_required=ssl_config.get("client_cert_required", False)
109
+ client_cert_required=ssl_config.get("client_cert_required", False),
103
110
  )
104
-
111
+
105
112
  self._current_transport = transport_type
106
-
107
- logger.info(f"Transport config loaded: {transport_type.value} on port {port}")
113
+
114
+ logger.info(
115
+ f"Transport config loaded: {transport_type.value} on port {port}"
116
+ )
108
117
  return True
109
-
118
+
110
119
  except Exception as e:
111
120
  logger.error(f"Failed to load transport config: {e}")
112
121
  return False
113
-
122
+
114
123
  def get_transport_type(self) -> Optional[TransportType]:
115
124
  """
116
125
  Get current transport type.
117
-
126
+
118
127
  Returns:
119
128
  Current transport type or None if not configured
120
129
  """
121
130
  return self._current_transport
122
-
131
+
123
132
  def get_port(self) -> Optional[int]:
124
133
  """
125
134
  Get configured port.
126
-
135
+
127
136
  Returns:
128
137
  Port number or None if not configured
129
138
  """
130
139
  return self._config.port if self._config else None
131
-
140
+
132
141
  def is_ssl_enabled(self) -> bool:
133
142
  """
134
143
  Check if SSL is enabled.
135
-
144
+
136
145
  Returns:
137
146
  True if SSL is enabled, False otherwise
138
147
  """
139
148
  return self._config.ssl_enabled if self._config else False
140
-
149
+
141
150
  def get_ssl_config(self) -> Optional[Dict[str, Any]]:
142
151
  """
143
152
  Get SSL configuration.
144
-
153
+
145
154
  Returns:
146
155
  SSL configuration dict or None if SSL not enabled
147
156
  """
148
157
  if not self._config or not self._config.ssl_enabled:
149
158
  return None
150
-
159
+
151
160
  return {
152
161
  "cert_file": self._config.cert_file,
153
162
  "key_file": self._config.key_file,
154
163
  "ca_cert": self._config.ca_cert,
155
164
  "verify_client": self._config.verify_client,
156
- "client_cert_required": self._config.client_cert_required
165
+ "client_cert_required": self._config.client_cert_required,
157
166
  }
158
-
167
+
159
168
  def is_mtls(self) -> bool:
160
169
  """
161
170
  Check if current transport is MTLS.
162
-
171
+
163
172
  Returns:
164
173
  True if MTLS transport, False otherwise
165
174
  """
166
175
  return self._current_transport == TransportType.MTLS
167
-
176
+
168
177
  def is_https(self) -> bool:
169
178
  """
170
179
  Check if current transport is HTTPS.
171
-
180
+
172
181
  Returns:
173
182
  True if HTTPS transport, False otherwise
174
183
  """
175
184
  return self._current_transport == TransportType.HTTPS
176
-
185
+
177
186
  def is_http(self) -> bool:
178
187
  """
179
188
  Check if current transport is HTTP.
180
-
189
+
181
190
  Returns:
182
191
  True if HTTP transport, False otherwise
183
192
  """
184
193
  return self._current_transport == TransportType.HTTP
185
-
194
+
186
195
  def get_transport_info(self) -> Dict[str, Any]:
187
196
  """
188
197
  Get transport information.
189
-
198
+
190
199
  Returns:
191
200
  Dictionary with transport information
192
201
  """
193
202
  if not self._config:
194
203
  return {"error": "Transport not configured"}
195
-
204
+
196
205
  return {
197
206
  "type": self._config.type.value,
198
207
  "port": self._config.port,
@@ -200,55 +209,57 @@ class TransportManager:
200
209
  "is_mtls": self.is_mtls(),
201
210
  "is_https": self.is_https(),
202
211
  "is_http": self.is_http(),
203
- "ssl_config": self.get_ssl_config()
212
+ "ssl_config": self.get_ssl_config(),
204
213
  }
205
-
214
+
206
215
  def validate_config(self) -> bool:
207
216
  """
208
217
  Validate current transport configuration.
209
-
218
+
210
219
  Returns:
211
220
  True if configuration is valid, False otherwise
212
221
  """
213
222
  if not self._config:
214
223
  logger.error("Transport not configured")
215
224
  return False
216
-
225
+
217
226
  # Validate SSL requirements
218
227
  if self._config.type in [TransportType.HTTPS, TransportType.MTLS]:
219
228
  if not self._config.ssl_enabled:
220
229
  logger.error(f"SSL must be enabled for {self._config.type.value}")
221
230
  return False
222
-
231
+
223
232
  if not self._config.cert_file or not self._config.key_file:
224
- logger.error(f"SSL certificate and key required for {self._config.type.value}")
233
+ logger.error(
234
+ f"SSL certificate and key required for {self._config.type.value}"
235
+ )
225
236
  return False
226
-
237
+
227
238
  # Validate SSL files exist
228
239
  if not self.validate_ssl_files():
229
240
  return False
230
-
241
+
231
242
  # Validate MTLS requirements
232
243
  if self._config.type == TransportType.MTLS:
233
244
  if not self._config.verify_client:
234
245
  logger.warning("MTLS transport should have client verification enabled")
235
-
246
+
236
247
  if not self._config.ca_cert:
237
248
  logger.warning("CA certificate recommended for MTLS transport")
238
-
249
+
239
250
  logger.info(f"Transport configuration validated: {self._config.type.value}")
240
251
  return True
241
-
252
+
242
253
  def validate_ssl_files(self) -> bool:
243
254
  """
244
255
  Check if SSL files exist.
245
-
256
+
246
257
  Returns:
247
258
  True if all SSL files exist, False otherwise
248
259
  """
249
260
  if not self._config or not self._config.ssl_enabled:
250
261
  return True
251
-
262
+
252
263
  files_to_check = []
253
264
  if self._config.cert_file:
254
265
  files_to_check.append(self._config.cert_file)
@@ -256,37 +267,38 @@ class TransportManager:
256
267
  files_to_check.append(self._config.key_file)
257
268
  if self._config.ca_cert:
258
269
  files_to_check.append(self._config.ca_cert)
259
-
270
+
260
271
  for file_path in files_to_check:
261
272
  if not Path(file_path).exists():
262
273
  logger.error(f"SSL file not found: {file_path}")
263
274
  return False
264
-
275
+
265
276
  logger.info(f"All SSL files validated successfully: {files_to_check}")
266
277
  return True
267
-
278
+
268
279
  def get_hypercorn_config(self) -> Dict[str, Any]:
269
280
  """
270
281
  Get configuration for hypercorn.
271
-
282
+
272
283
  Returns:
273
284
  Hypercorn configuration dictionary
274
285
  """
275
286
  config = {
276
287
  "host": "0.0.0.0", # Can be moved to settings
277
288
  "port": self.get_port(),
278
- "log_level": "info"
289
+ "log_level": "info",
279
290
  }
280
-
291
+
281
292
  if self.is_ssl_enabled():
282
293
  ssl_config = self.get_ssl_config()
283
294
  if ssl_config:
284
295
  from mcp_proxy_adapter.core.ssl_utils import SSLUtils
296
+
285
297
  hypercorn_ssl = SSLUtils.get_ssl_config_for_hypercorn(ssl_config)
286
298
  config.update(hypercorn_ssl)
287
-
299
+
288
300
  return config
289
301
 
290
302
 
291
303
  # Global transport manager instance
292
- transport_manager = TransportManager()
304
+ transport_manager = TransportManager()