mcp-proxy-adapter 6.9.28__py3-none-any.whl → 6.9.30__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.

Potentially problematic release.


This version of mcp-proxy-adapter might be problematic. Click here for more details.

Files changed (212) hide show
  1. mcp_proxy_adapter/__init__.py +10 -0
  2. mcp_proxy_adapter/__main__.py +8 -21
  3. mcp_proxy_adapter/api/app.py +10 -913
  4. mcp_proxy_adapter/api/core/__init__.py +18 -0
  5. mcp_proxy_adapter/api/core/app_factory.py +243 -0
  6. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  7. mcp_proxy_adapter/api/core/registration_manager.py +166 -0
  8. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  9. mcp_proxy_adapter/api/handlers.py +78 -199
  10. mcp_proxy_adapter/api/middleware/__init__.py +1 -44
  11. mcp_proxy_adapter/api/middleware/base.py +0 -42
  12. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
  13. mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
  14. mcp_proxy_adapter/api/middleware/factory.py +0 -94
  15. mcp_proxy_adapter/api/middleware/logging.py +0 -112
  16. mcp_proxy_adapter/api/middleware/performance.py +0 -35
  17. mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
  18. mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
  19. mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
  20. mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
  21. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  22. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  23. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  24. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  25. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  26. mcp_proxy_adapter/api/schemas.py +0 -61
  27. mcp_proxy_adapter/api/tool_integration.py +0 -117
  28. mcp_proxy_adapter/api/tools.py +0 -46
  29. mcp_proxy_adapter/cli/__init__.py +12 -0
  30. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  31. mcp_proxy_adapter/cli/commands/client.py +100 -0
  32. mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
  33. mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
  34. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  35. mcp_proxy_adapter/cli/commands/server.py +174 -0
  36. mcp_proxy_adapter/cli/commands/sets.py +128 -0
  37. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  38. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  39. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  40. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  41. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  42. mcp_proxy_adapter/cli/main.py +63 -0
  43. mcp_proxy_adapter/cli/parser.py +324 -0
  44. mcp_proxy_adapter/cli/validators.py +231 -0
  45. mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
  46. mcp_proxy_adapter/client/proxy.py +45 -0
  47. mcp_proxy_adapter/commands/__init__.py +44 -28
  48. mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
  49. mcp_proxy_adapter/commands/base.py +19 -43
  50. mcp_proxy_adapter/commands/builtin_commands.py +0 -75
  51. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  52. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  53. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  54. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  55. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  56. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  57. mcp_proxy_adapter/commands/catalog_manager.py +58 -928
  58. mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
  59. mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
  60. mcp_proxy_adapter/commands/command_registry.py +172 -904
  61. mcp_proxy_adapter/commands/config_command.py +0 -28
  62. mcp_proxy_adapter/commands/dependency_container.py +1 -70
  63. mcp_proxy_adapter/commands/dependency_manager.py +0 -128
  64. mcp_proxy_adapter/commands/echo_command.py +0 -34
  65. mcp_proxy_adapter/commands/health_command.py +0 -3
  66. mcp_proxy_adapter/commands/help_command.py +0 -159
  67. mcp_proxy_adapter/commands/hooks.py +0 -137
  68. mcp_proxy_adapter/commands/key_management_command.py +0 -25
  69. mcp_proxy_adapter/commands/load_command.py +7 -78
  70. mcp_proxy_adapter/commands/plugins_command.py +0 -16
  71. mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
  72. mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
  73. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  74. mcp_proxy_adapter/commands/registration_status_command.py +0 -43
  75. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  76. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  77. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  78. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  79. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  80. mcp_proxy_adapter/commands/reload_command.py +0 -80
  81. mcp_proxy_adapter/commands/result.py +25 -77
  82. mcp_proxy_adapter/commands/role_test_command.py +0 -44
  83. mcp_proxy_adapter/commands/roles_management_command.py +0 -199
  84. mcp_proxy_adapter/commands/security_command.py +0 -30
  85. mcp_proxy_adapter/commands/settings_command.py +0 -68
  86. mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
  87. mcp_proxy_adapter/commands/token_management_command.py +0 -1
  88. mcp_proxy_adapter/commands/transport_management_command.py +0 -20
  89. mcp_proxy_adapter/commands/unload_command.py +0 -71
  90. mcp_proxy_adapter/config.py +15 -626
  91. mcp_proxy_adapter/core/__init__.py +5 -39
  92. mcp_proxy_adapter/core/app_factory.py +14 -36
  93. mcp_proxy_adapter/core/app_runner.py +0 -27
  94. mcp_proxy_adapter/core/auth_validator.py +1 -93
  95. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  96. mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
  97. mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
  98. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  99. mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
  100. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
  101. mcp_proxy_adapter/core/certificate_utils.py +64 -903
  102. mcp_proxy_adapter/core/client.py +10 -9
  103. mcp_proxy_adapter/core/client_manager.py +0 -19
  104. mcp_proxy_adapter/core/client_security.py +0 -2
  105. mcp_proxy_adapter/core/config/__init__.py +18 -0
  106. mcp_proxy_adapter/core/config/config.py +195 -0
  107. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  108. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  109. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  110. mcp_proxy_adapter/core/config/simple_config.py +112 -0
  111. mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
  112. mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
  113. mcp_proxy_adapter/core/config_converter.py +0 -186
  114. mcp_proxy_adapter/core/config_validator.py +96 -1238
  115. mcp_proxy_adapter/core/errors.py +7 -42
  116. mcp_proxy_adapter/core/job_manager.py +54 -0
  117. mcp_proxy_adapter/core/logging.py +2 -22
  118. mcp_proxy_adapter/core/mtls_asgi.py +0 -20
  119. mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
  120. mcp_proxy_adapter/core/mtls_proxy.py +0 -80
  121. mcp_proxy_adapter/core/mtls_server.py +3 -173
  122. mcp_proxy_adapter/core/protocol_manager.py +1 -191
  123. mcp_proxy_adapter/core/proxy/__init__.py +22 -0
  124. mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
  125. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
  126. mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
  127. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  128. mcp_proxy_adapter/core/proxy_client.py +0 -1
  129. mcp_proxy_adapter/core/proxy_registration.py +36 -913
  130. mcp_proxy_adapter/core/role_utils.py +0 -308
  131. mcp_proxy_adapter/core/security_adapter.py +1 -36
  132. mcp_proxy_adapter/core/security_factory.py +1 -150
  133. mcp_proxy_adapter/core/security_integration.py +0 -33
  134. mcp_proxy_adapter/core/server_adapter.py +1 -40
  135. mcp_proxy_adapter/core/server_engine.py +2 -173
  136. mcp_proxy_adapter/core/settings.py +0 -127
  137. mcp_proxy_adapter/core/signal_handler.py +0 -65
  138. mcp_proxy_adapter/core/ssl_utils.py +19 -137
  139. mcp_proxy_adapter/core/transport_manager.py +0 -151
  140. mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
  141. mcp_proxy_adapter/core/utils.py +1 -182
  142. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  143. mcp_proxy_adapter/core/validation/config_validator.py +211 -0
  144. mcp_proxy_adapter/core/validation/file_validator.py +73 -0
  145. mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
  146. mcp_proxy_adapter/core/validation/security_validator.py +58 -0
  147. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  148. mcp_proxy_adapter/custom_openapi.py +33 -652
  149. mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
  150. mcp_proxy_adapter/examples/check_config.py +0 -2
  151. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  152. mcp_proxy_adapter/examples/config_builder.py +13 -2
  153. mcp_proxy_adapter/examples/config_cli.py +0 -1
  154. mcp_proxy_adapter/examples/create_test_configs.py +0 -46
  155. mcp_proxy_adapter/examples/debug_request_state.py +0 -1
  156. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
  157. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
  158. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
  159. mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
  160. mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
  161. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
  162. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
  163. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
  164. mcp_proxy_adapter/examples/full_application/main.py +186 -150
  165. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
  166. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
  167. mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
  168. mcp_proxy_adapter/examples/generate_config.py +65 -11
  169. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  170. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  171. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  172. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  173. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  174. mcp_proxy_adapter/examples/required_certificates.py +0 -2
  175. mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
  176. mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
  177. mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
  178. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  179. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  180. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  181. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  182. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  183. mcp_proxy_adapter/examples/security_test_client.py +24 -1075
  184. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  185. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  186. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  187. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  188. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  189. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  190. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  191. mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
  192. mcp_proxy_adapter/examples/test_config.py +0 -3
  193. mcp_proxy_adapter/examples/test_config_builder.py +25 -405
  194. mcp_proxy_adapter/examples/test_examples.py +0 -1
  195. mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
  196. mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
  197. mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
  198. mcp_proxy_adapter/examples/universal_client.py +0 -6
  199. mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
  200. mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
  201. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
  202. mcp_proxy_adapter/integrations/__init__.py +25 -0
  203. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  204. mcp_proxy_adapter/main.py +70 -62
  205. mcp_proxy_adapter/openapi.py +0 -22
  206. mcp_proxy_adapter/version.py +1 -1
  207. {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/METADATA +2 -1
  208. mcp_proxy_adapter-6.9.30.dist-info/RECORD +235 -0
  209. {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/entry_points.txt +1 -1
  210. mcp_proxy_adapter-6.9.28.dist-info/RECORD +0 -149
  211. {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/WHEEL +0 -0
  212. {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/top_level.txt +0 -0
@@ -2,8 +2,8 @@
2
2
  Module for defining errors and exceptions for the microservice.
3
3
  """
4
4
 
5
- from typing import Any, Dict, List, Optional, Union
6
5
  from dataclasses import dataclass
6
+ from typing import Any, Dict, List, Optional
7
7
 
8
8
 
9
9
  class MicroserviceError(Exception):
@@ -33,20 +33,17 @@ class MicroserviceError(Exception):
33
33
  super().__init__(message)
34
34
 
35
35
  def to_dict(self) -> Dict[str, Any]:
36
- """
37
- Converts the error to a dictionary for JSON-RPC response.
38
-
39
- Returns:
40
- Dictionary with error information.
41
- """
42
- result = {"code": self.code, "message": self.message}
43
-
36
+ """Convert error to dictionary format."""
37
+ result = {
38
+ "code": self.code,
39
+ "message": self.message
40
+ }
44
41
  if self.data:
45
42
  result["data"] = self.data
46
-
47
43
  return result
48
44
 
49
45
 
46
+
50
47
  class ParseError(MicroserviceError):
51
48
  """
52
49
  Error while parsing JSON request.
@@ -199,23 +196,6 @@ class TimeoutError(MicroserviceError):
199
196
  super().__init__(message, code=-32003, data=data)
200
197
 
201
198
 
202
- def format_validation_errors(errors: List[Dict[str, Any]]) -> Dict[str, Any]:
203
- """
204
- Formats validation errors into a standard format.
205
-
206
- Args:
207
- errors: List of validation errors.
208
-
209
- Returns:
210
- Formatted validation errors.
211
- """
212
- formatted_errors = {}
213
- for error in errors:
214
- loc = error.get("loc", [])
215
- field = ".".join(str(item) for item in loc)
216
- msg = error.get("msg", "Validation error")
217
- formatted_errors[field] = msg
218
- return formatted_errors
219
199
 
220
200
 
221
201
  @dataclass
@@ -242,21 +222,6 @@ class ConfigError(MicroserviceError):
242
222
  super().__init__(message, code=-32001, data={"type": "configuration_error"})
243
223
  self.validation_results = validation_results or []
244
224
 
245
- def get_error_summary(self) -> str:
246
- """Get summary of all validation errors."""
247
- if not self.validation_results:
248
- return self.message
249
-
250
- error_messages = []
251
- for result in self.validation_results:
252
- if result.level == "error":
253
- location = f"{result.section}.{result.key}" if result.key else result.section
254
- error_msg = f"[{location}] {result.message}"
255
- if result.suggestion:
256
- error_msg += f" (Suggestion: {result.suggestion})"
257
- error_messages.append(error_msg)
258
-
259
- return "\n".join(error_messages)
260
225
 
261
226
 
262
227
  class MissingConfigKeyError(ConfigError):
@@ -0,0 +1,54 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Simple in-memory job manager for long-running demo commands.
6
+ Not for production use.
7
+ """
8
+
9
+ import asyncio
10
+ import uuid
11
+ from typing import Any, Dict, Optional, Awaitable
12
+
13
+
14
+ class JobRecord:
15
+ def __init__(self, task: asyncio.Task):
16
+ self.task = task
17
+ self.status = "running"
18
+ self.result: Optional[Any] = None
19
+ self.error: Optional[str] = None
20
+
21
+
22
+ _jobs: Dict[str, JobRecord] = {}
23
+
24
+
25
+ def enqueue_coroutine(coro: Awaitable[Any]) -> str:
26
+ job_id = str(uuid.uuid4())
27
+ task = asyncio.create_task(_run_job(job_id, coro))
28
+ _jobs[job_id] = JobRecord(task)
29
+ return job_id
30
+
31
+
32
+ async def _run_job(job_id: str, coro):
33
+ rec = _jobs[job_id]
34
+ try:
35
+ rec.result = await coro
36
+ rec.status = "completed"
37
+ except Exception as exc: # noqa: BLE001
38
+ rec.error = str(exc)
39
+ rec.status = "failed"
40
+
41
+
42
+ def get_job_status(job_id: str) -> Dict[str, Any]:
43
+ rec = _jobs.get(job_id)
44
+ if not rec:
45
+ return {"exists": False}
46
+ return {
47
+ "exists": True,
48
+ "status": rec.status,
49
+ "done": rec.task.done(),
50
+ "result": rec.result,
51
+ "error": rec.error,
52
+ }
53
+
54
+
@@ -6,10 +6,8 @@ import logging
6
6
  import os
7
7
  import sys
8
8
  import uuid
9
- from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler
10
- from typing import Dict, Optional, Any
11
-
12
- from mcp_proxy_adapter.config import get_config
9
+ from logging.handlers import RotatingFileHandler
10
+ from typing import Optional
13
11
 
14
12
 
15
13
  class CustomFormatter(logging.Formatter):
@@ -47,11 +45,6 @@ class RequestContextFilter(logging.Filter):
47
45
  super().__init__()
48
46
  self.request_id = request_id
49
47
 
50
- def filter(self, record):
51
- # Add request_id attribute to the record
52
- record.request_id = self.request_id or "no-request-id"
53
- return True
54
-
55
48
 
56
49
  class RequestLogger:
57
50
  """
@@ -245,19 +238,6 @@ def _parse_file_size(size_str) -> int:
245
238
  return int(size_str)
246
239
 
247
240
 
248
- def get_logger(name: str) -> logging.Logger:
249
- """
250
- Get a get_global_logger() with the specified name.
251
-
252
- Args:
253
- name: Logger name.
254
-
255
- Returns:
256
- Configured get_global_logger() instance.
257
- """
258
- return logging.getLogger(name)
259
-
260
-
261
241
  # Global get_global_logger() for use throughout the application
262
242
  # Initialize lazily to avoid import-time errors
263
243
  logger = None
@@ -8,9 +8,6 @@ client certificates in mTLS connections.
8
8
  import ssl
9
9
  import logging
10
10
  from typing import Dict, Any, Optional
11
- from starlette.applications import Starlette
12
- from starlette.requests import Request
13
- from starlette.responses import Response
14
11
  from starlette.types import ASGIApp, Receive, Send, Scope
15
12
 
16
13
  logger = logging.getLogger(__name__)
@@ -141,20 +138,3 @@ class MTLSASGIApp:
141
138
  await send({"type": "http.response.body", "body": body})
142
139
 
143
140
 
144
- def create_mtls_asgi_app(app: ASGIApp, ssl_config: Dict[str, Any]) -> ASGIApp:
145
- """
146
- Create MTLS-enabled ASGI application.
147
-
148
- Args:
149
- app: The underlying ASGI application (FastAPI)
150
- ssl_config: SSL configuration for mTLS
151
-
152
- Returns:
153
- MTLS-enabled ASGI application
154
- """
155
- if ssl_config.get("mode") == "mtls" or ssl_config.get("verify_client", False):
156
- get_global_logger().info("Creating MTLS-enabled ASGI application")
157
- return MTLSASGIApp(app, ssl_config)
158
- else:
159
- get_global_logger().info("Creating standard ASGI application (no mTLS)")
160
- return app
@@ -185,15 +185,3 @@ class MTLSASGIApp:
185
185
  await send({"type": "http.response.body", "body": body})
186
186
 
187
187
 
188
- def create_mtls_asgi_app(app, ssl_config: Dict[str, Any]):
189
- """
190
- Create MTLS ASGI application wrapper.
191
-
192
- Args:
193
- app: The underlying ASGI application
194
- ssl_config: SSL configuration dictionary
195
-
196
- Returns:
197
- MTLS ASGI app wrapper
198
- """
199
- return MTLSASGIApp(app, ssl_config)
@@ -12,7 +12,6 @@ import asyncio
12
12
  import ssl
13
13
  import logging
14
14
  from typing import Optional, Dict, Any
15
- from pathlib import Path
16
15
 
17
16
  logger = logging.getLogger(__name__)
18
17
 
@@ -79,39 +78,7 @@ class MTLSProxy:
79
78
  get_global_logger().error(f"❌ Failed to start mTLS proxy: {e}")
80
79
  raise
81
80
 
82
- async def stop(self):
83
- """Stop the mTLS proxy server."""
84
- if self.server:
85
- self.server.close()
86
- await self.server.wait_closed()
87
- get_global_logger().info("🔐 mTLS Proxy stopped")
88
81
 
89
- async def _handle_client(self, reader, writer):
90
- """Handle client connection."""
91
- try:
92
- # Get client address
93
- client_addr = writer.get_extra_info('peername')
94
- get_global_logger().info(f"🔐 mTLS connection from {client_addr}")
95
-
96
- # Connect to internal server
97
- internal_reader, internal_writer = await asyncio.open_connection(
98
- self.internal_host, self.internal_port
99
- )
100
-
101
- # Create bidirectional proxy
102
- await asyncio.gather(
103
- self._proxy_data(reader, internal_writer, "client->server"),
104
- self._proxy_data(internal_reader, writer, "server->client")
105
- )
106
-
107
- except Exception as e:
108
- get_global_logger().error(f"❌ Error handling client connection: {e}")
109
- finally:
110
- try:
111
- writer.close()
112
- await writer.wait_closed()
113
- except:
114
- pass
115
82
 
116
83
  async def _proxy_data(self, reader, writer, direction):
117
84
  """Proxy data between reader and writer."""
@@ -132,50 +99,3 @@ class MTLSProxy:
132
99
  pass
133
100
 
134
101
 
135
- async def start_mtls_proxy(config: Dict[str, Any]) -> Optional[MTLSProxy]:
136
- """
137
- Start mTLS proxy based on configuration.
138
-
139
- Args:
140
- config: Application configuration
141
-
142
- Returns:
143
- MTLSProxy instance if started, None otherwise
144
- """
145
- # Check if mTLS is enabled
146
- protocol = config.get("server", {}).get("protocol", "http")
147
- verify_client = config.get("transport", {}).get("verify_client", False)
148
-
149
- # Only start mTLS proxy if mTLS is explicitly enabled
150
- if protocol != "mtls" and not verify_client:
151
- get_global_logger().info("🌐 Regular mode: no mTLS proxy needed")
152
- return None
153
-
154
- # Get configuration
155
- server_config = config.get("server", {})
156
- transport_config = config.get("transport", {})
157
-
158
- external_host = server_config.get("host", "0.0.0.0")
159
- external_port = server_config.get("port", 8000)
160
- internal_port = external_port + 1000 # Internal port
161
-
162
- cert_file = transport_config.get("cert_file")
163
- key_file = transport_config.get("key_file")
164
- ca_cert = transport_config.get("ca_cert")
165
-
166
- if not cert_file or not key_file:
167
- get_global_logger().warning("⚠️ mTLS enabled but certificates not configured")
168
- return None
169
-
170
- # Create and start proxy
171
- proxy = MTLSProxy(
172
- external_host=external_host,
173
- external_port=external_port,
174
- internal_port=internal_port,
175
- cert_file=cert_file,
176
- key_file=key_file,
177
- ca_cert=ca_cert
178
- )
179
-
180
- await proxy.start()
181
- return proxy
@@ -24,84 +24,8 @@ class mTLSHandler(BaseHTTPRequestHandler):
24
24
  self.main_app = main_app
25
25
  super().__init__(*args, **kwargs)
26
26
 
27
- def log_message(self, format, *args):
28
- """Override to use our get_global_logger()."""
29
- get_global_logger().info(f"mTLS Server: {format % args}")
30
27
 
31
- def do_GET(self):
32
- """Handle GET requests."""
33
- try:
34
- # Get client certificate
35
- client_cert = None
36
- if hasattr(self.connection, "getpeercert"):
37
- client_cert = self.connection.getpeercert()
38
-
39
- # Process request through main app if available
40
- if self.main_app:
41
- # Forward to main FastAPI app
42
- response_data = self._forward_to_main_app(
43
- "GET", self.path, client_cert
44
- )
45
- else:
46
- # Simple response
47
- response_data = {
48
- "status": "ok",
49
- "message": "mTLS connection successful",
50
- "client_cert": client_cert,
51
- "path": self.path,
52
- }
53
-
54
- # Send response
55
- self.send_response(200)
56
- self.send_header("Content-type", "application/json")
57
- self.end_headers()
58
- self.wfile.write(json.dumps(response_data).encode())
59
28
 
60
- except Exception as e:
61
- get_global_logger().error(f"Error in mTLS GET handler: {e}")
62
- self.send_error(500, str(e))
63
-
64
- def do_POST(self):
65
- """Handle POST requests."""
66
- try:
67
- # Get content length
68
- content_length = int(self.headers.get("Content-Length", 0))
69
-
70
- # Read request body
71
- post_data = None
72
- if content_length > 0:
73
- post_data = self.rfile.read(content_length)
74
-
75
- # Get client certificate
76
- client_cert = None
77
- if hasattr(self.connection, "getpeercert"):
78
- client_cert = self.connection.getpeercert()
79
-
80
- # Process request through main app if available
81
- if self.main_app:
82
- # Forward to main FastAPI app
83
- response_data = self._forward_to_main_app(
84
- "POST", self.path, client_cert, post_data
85
- )
86
- else:
87
- # Simple response
88
- response_data = {
89
- "status": "ok",
90
- "message": "mTLS POST successful",
91
- "client_cert": client_cert,
92
- "path": self.path,
93
- "data_received": len(post_data) if post_data else 0,
94
- }
95
-
96
- # Send response
97
- self.send_response(200)
98
- self.send_header("Content-type", "application/json")
99
- self.end_headers()
100
- self.wfile.write(json.dumps(response_data).encode())
101
-
102
- except Exception as e:
103
- get_global_logger().error(f"Error in mTLS POST handler: {e}")
104
- self.send_error(500, str(e))
105
29
 
106
30
  def _forward_to_main_app(
107
31
  self,
@@ -172,8 +96,6 @@ class mTLSServer:
172
96
  def _create_handler(self):
173
97
  """Create handler with main app reference."""
174
98
 
175
- def handler(*args, **kwargs):
176
- return mTLSHandler(*args, main_app=self.main_app, **kwargs)
177
99
 
178
100
  return handler
179
101
 
@@ -226,99 +148,7 @@ class mTLSServer:
226
148
  get_global_logger().error(f"Failed to start mTLS server: {e}")
227
149
  return False
228
150
 
229
- def _run_server(self):
230
- """Run the server (blocking)."""
231
- try:
232
- get_global_logger().info(
233
- f"mTLS Server listening on https://{self.host}:{self.port}"
234
- )
235
- self.server.serve_forever()
236
- except Exception as e:
237
- get_global_logger().error(f"mTLS Server error: {e}")
238
- finally:
239
- self.running = False
240
-
241
- def stop(self):
242
- """Stop mTLS server."""
243
- if self.server and self.running:
244
- try:
245
- self.server.shutdown()
246
- self.server.server_close()
247
- self.running = False
248
- get_global_logger().info("✅ mTLS Server stopped")
249
- except Exception as e:
250
- get_global_logger().error(f"Error stopping mTLS server: {e}")
251
-
252
- def is_running(self) -> bool:
253
- """Check if server is running."""
254
- return (
255
- self.running
256
- and self.server_thread
257
- and self.server_thread.is_alive()
258
- )
259
-
260
-
261
- def start_mtls_server_thread(
262
- config: Dict[str, Any], main_app=None
263
- ) -> Optional[mTLSServer]:
264
- """
265
- Start mTLS server in separate thread.
266
-
267
- Args:
268
- config: Configuration dictionary
269
- main_app: Main FastAPI application
270
-
271
- Returns:
272
- mTLSServer instance or None if failed
273
- """
274
- try:
275
- # Extract SSL configuration
276
- ssl_config = config.get("ssl", {})
277
-
278
- # Check if mTLS is enabled
279
- verify_client = ssl_config.get("verify_client", False)
280
- if not verify_client:
281
- get_global_logger().info(
282
- "mTLS not enabled (verify_client=False), skipping mTLS server"
283
- )
284
- return None
285
-
286
- # Get server configuration
287
- server_config = config.get("server", {})
288
- host = server_config.get("host", "127.0.0.1")
289
- preferred_port = ssl_config.get("mtls_port", 8443) # Different port for mTLS
290
-
291
- # For internal servers (mTLS), find available port if preferred is occupied
292
- from mcp_proxy_adapter.core.utils import find_port_for_internal_server
293
- port = find_port_for_internal_server(host, preferred_port)
294
-
295
- # Get certificate paths - all required for mTLS
296
- cert_file = ssl_config.get("cert_file")
297
- key_file = ssl_config.get("key_file")
298
- ca_cert_file = ssl_config.get("ca_cert")
299
-
300
- if not cert_file or not key_file:
301
- raise ValueError(
302
- "mTLS server requires SSL certificate configuration. "
303
- "Please configure 'ssl.cert_file' and 'ssl.key_file' in your configuration file."
304
- )
305
151
 
306
- # Create and start mTLS server
307
- mtls_server = mTLSServer(
308
- host=host,
309
- port=port,
310
- cert_file=cert_file,
311
- key_file=key_file,
312
- ca_cert_file=ca_cert_file,
313
- main_app=main_app,
314
- )
315
-
316
- if mtls_server.start():
317
- return mtls_server
318
- else:
319
- get_global_logger().error("Failed to start mTLS server")
320
- return None
321
-
322
- except Exception as e:
323
- get_global_logger().error(f"Error starting mTLS server thread: {e}")
324
- return None
152
+
153
+
154
+