mcp-proxy-adapter 2.0.1__py3-none-any.whl → 6.9.50__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 (269) hide show
  1. mcp_proxy_adapter/__init__.py +47 -0
  2. mcp_proxy_adapter/__main__.py +13 -0
  3. mcp_proxy_adapter/api/__init__.py +0 -0
  4. mcp_proxy_adapter/api/app.py +66 -0
  5. mcp_proxy_adapter/api/core/__init__.py +18 -0
  6. mcp_proxy_adapter/api/core/app_factory.py +400 -0
  7. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  8. mcp_proxy_adapter/api/core/registration_context.py +356 -0
  9. mcp_proxy_adapter/api/core/registration_manager.py +307 -0
  10. mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
  11. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  12. mcp_proxy_adapter/api/handlers.py +181 -0
  13. mcp_proxy_adapter/api/middleware/__init__.py +21 -0
  14. mcp_proxy_adapter/api/middleware/base.py +54 -0
  15. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
  16. mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
  17. mcp_proxy_adapter/api/middleware/factory.py +147 -0
  18. mcp_proxy_adapter/api/middleware/logging.py +31 -0
  19. mcp_proxy_adapter/api/middleware/performance.py +51 -0
  20. mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
  21. mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
  22. mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
  23. mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
  24. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  25. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  26. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  27. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  28. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  29. mcp_proxy_adapter/api/schemas.py +270 -0
  30. mcp_proxy_adapter/api/tool_integration.py +131 -0
  31. mcp_proxy_adapter/api/tools.py +163 -0
  32. mcp_proxy_adapter/cli/__init__.py +12 -0
  33. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  34. mcp_proxy_adapter/cli/commands/client.py +100 -0
  35. mcp_proxy_adapter/cli/commands/config_generate.py +105 -0
  36. mcp_proxy_adapter/cli/commands/config_validate.py +94 -0
  37. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  38. mcp_proxy_adapter/cli/commands/server.py +174 -0
  39. mcp_proxy_adapter/cli/commands/sets.py +132 -0
  40. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  41. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  42. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  43. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  44. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  45. mcp_proxy_adapter/cli/main.py +63 -0
  46. mcp_proxy_adapter/cli/parser.py +338 -0
  47. mcp_proxy_adapter/cli/validators.py +231 -0
  48. mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
  49. mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
  50. mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
  51. mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
  52. mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
  53. mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
  54. mcp_proxy_adapter/client/proxy.py +123 -0
  55. mcp_proxy_adapter/commands/__init__.py +66 -0
  56. mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
  57. mcp_proxy_adapter/commands/base.py +389 -0
  58. mcp_proxy_adapter/commands/builtin_commands.py +30 -0
  59. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  60. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  61. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  62. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  63. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  64. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  65. mcp_proxy_adapter/commands/catalog_manager.py +97 -0
  66. mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
  67. mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
  68. mcp_proxy_adapter/commands/command_registry.py +298 -0
  69. mcp_proxy_adapter/commands/config_command.py +102 -0
  70. mcp_proxy_adapter/commands/dependency_container.py +40 -0
  71. mcp_proxy_adapter/commands/dependency_manager.py +143 -0
  72. mcp_proxy_adapter/commands/echo_command.py +48 -0
  73. mcp_proxy_adapter/commands/health_command.py +142 -0
  74. mcp_proxy_adapter/commands/help_command.py +175 -0
  75. mcp_proxy_adapter/commands/hooks.py +172 -0
  76. mcp_proxy_adapter/commands/key_management_command.py +484 -0
  77. mcp_proxy_adapter/commands/load_command.py +123 -0
  78. mcp_proxy_adapter/commands/plugins_command.py +246 -0
  79. mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
  80. mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
  81. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  82. mcp_proxy_adapter/commands/registration_status_command.py +76 -0
  83. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  84. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  85. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  86. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  87. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  88. mcp_proxy_adapter/commands/reload_command.py +136 -0
  89. mcp_proxy_adapter/commands/result.py +157 -0
  90. mcp_proxy_adapter/commands/role_test_command.py +99 -0
  91. mcp_proxy_adapter/commands/roles_management_command.py +502 -0
  92. mcp_proxy_adapter/commands/security_command.py +472 -0
  93. mcp_proxy_adapter/commands/settings_command.py +113 -0
  94. mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
  95. mcp_proxy_adapter/commands/token_management_command.py +500 -0
  96. mcp_proxy_adapter/commands/transport_management_command.py +129 -0
  97. mcp_proxy_adapter/commands/unload_command.py +92 -0
  98. mcp_proxy_adapter/config.py +32 -0
  99. mcp_proxy_adapter/core/__init__.py +8 -0
  100. mcp_proxy_adapter/core/app_factory.py +560 -0
  101. mcp_proxy_adapter/core/app_runner.py +318 -0
  102. mcp_proxy_adapter/core/auth_validator.py +508 -0
  103. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  104. mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
  105. mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
  106. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  107. mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
  108. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
  109. mcp_proxy_adapter/core/certificate_utils.py +249 -0
  110. mcp_proxy_adapter/core/client.py +608 -0
  111. mcp_proxy_adapter/core/client_manager.py +271 -0
  112. mcp_proxy_adapter/core/client_security.py +411 -0
  113. mcp_proxy_adapter/core/config/__init__.py +18 -0
  114. mcp_proxy_adapter/core/config/config.py +237 -0
  115. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  116. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  117. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  118. mcp_proxy_adapter/core/config/simple_config.py +204 -0
  119. mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
  120. mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
  121. mcp_proxy_adapter/core/config_converter.py +252 -0
  122. mcp_proxy_adapter/core/config_validator.py +211 -0
  123. mcp_proxy_adapter/core/crl_utils.py +362 -0
  124. mcp_proxy_adapter/core/errors.py +276 -0
  125. mcp_proxy_adapter/core/job_manager.py +54 -0
  126. mcp_proxy_adapter/core/logging.py +250 -0
  127. mcp_proxy_adapter/core/mtls_asgi.py +140 -0
  128. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  129. mcp_proxy_adapter/core/mtls_proxy.py +229 -0
  130. mcp_proxy_adapter/core/mtls_server.py +154 -0
  131. mcp_proxy_adapter/core/protocol_manager.py +232 -0
  132. mcp_proxy_adapter/core/proxy/__init__.py +19 -0
  133. mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
  134. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
  135. mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
  136. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  137. mcp_proxy_adapter/core/proxy_client.py +184 -0
  138. mcp_proxy_adapter/core/proxy_registration.py +80 -0
  139. mcp_proxy_adapter/core/role_utils.py +103 -0
  140. mcp_proxy_adapter/core/security_adapter.py +343 -0
  141. mcp_proxy_adapter/core/security_factory.py +96 -0
  142. mcp_proxy_adapter/core/security_integration.py +342 -0
  143. mcp_proxy_adapter/core/server_adapter.py +251 -0
  144. mcp_proxy_adapter/core/server_engine.py +217 -0
  145. mcp_proxy_adapter/core/settings.py +260 -0
  146. mcp_proxy_adapter/core/signal_handler.py +107 -0
  147. mcp_proxy_adapter/core/ssl_utils.py +161 -0
  148. mcp_proxy_adapter/core/transport_manager.py +153 -0
  149. mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
  150. mcp_proxy_adapter/core/utils.py +101 -0
  151. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  152. mcp_proxy_adapter/core/validation/config_validator.py +219 -0
  153. mcp_proxy_adapter/core/validation/file_validator.py +131 -0
  154. mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
  155. mcp_proxy_adapter/core/validation/security_validator.py +140 -0
  156. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  157. mcp_proxy_adapter/custom_openapi.py +58 -0
  158. mcp_proxy_adapter/examples/__init__.py +16 -0
  159. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  160. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  161. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  162. mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
  163. mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
  164. mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
  165. mcp_proxy_adapter/examples/check_config.py +413 -0
  166. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  167. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  168. mcp_proxy_adapter/examples/config_builder.py +234 -0
  169. mcp_proxy_adapter/examples/config_cli.py +282 -0
  170. mcp_proxy_adapter/examples/create_test_configs.py +174 -0
  171. mcp_proxy_adapter/examples/debug_request_state.py +130 -0
  172. mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
  173. mcp_proxy_adapter/examples/demo_client.py +287 -0
  174. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  175. mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
  176. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
  177. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
  178. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
  179. mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
  180. mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
  181. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
  182. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
  183. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
  184. mcp_proxy_adapter/examples/full_application/main.py +311 -0
  185. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
  186. mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
  187. mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
  188. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
  189. mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
  190. mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
  191. mcp_proxy_adapter/examples/generate_config.py +502 -0
  192. mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
  193. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  194. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  195. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  196. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  197. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  198. mcp_proxy_adapter/examples/required_certificates.py +208 -0
  199. mcp_proxy_adapter/examples/run_example.py +77 -0
  200. mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
  201. mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
  202. mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
  203. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  204. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  205. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  206. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  207. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  208. mcp_proxy_adapter/examples/security_test_client.py +72 -0
  209. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  210. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  211. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  212. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  213. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  214. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  215. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  216. mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
  217. mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
  218. mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
  219. mcp_proxy_adapter/examples/test_config.py +205 -0
  220. mcp_proxy_adapter/examples/test_config_builder.py +110 -0
  221. mcp_proxy_adapter/examples/test_examples.py +308 -0
  222. mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
  223. mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
  224. mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
  225. mcp_proxy_adapter/examples/universal_client.py +674 -0
  226. mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
  227. mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
  228. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
  229. mcp_proxy_adapter/integrations/__init__.py +25 -0
  230. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  231. mcp_proxy_adapter/main.py +311 -0
  232. mcp_proxy_adapter/openapi.py +375 -0
  233. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  234. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  235. mcp_proxy_adapter/schemas/roles.json +37 -0
  236. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  237. mcp_proxy_adapter/version.py +5 -0
  238. mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
  239. mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
  240. {mcp_proxy_adapter-2.0.1.dist-info → mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
  241. mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
  242. mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
  243. adapters/__init__.py +0 -16
  244. analyzers/__init__.py +0 -14
  245. analyzers/docstring_analyzer.py +0 -199
  246. analyzers/type_analyzer.py +0 -151
  247. cli/__init__.py +0 -12
  248. cli/__main__.py +0 -79
  249. cli/command_runner.py +0 -233
  250. dispatchers/__init__.py +0 -14
  251. dispatchers/base_dispatcher.py +0 -85
  252. dispatchers/json_rpc_dispatcher.py +0 -198
  253. generators/__init__.py +0 -14
  254. generators/endpoint_generator.py +0 -172
  255. generators/openapi_generator.py +0 -254
  256. generators/rest_api_generator.py +0 -207
  257. mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
  258. mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
  259. mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
  260. mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
  261. openapi_schema/__init__.py +0 -38
  262. openapi_schema/command_registry.py +0 -312
  263. openapi_schema/rest_schema.py +0 -510
  264. openapi_schema/rpc_generator.py +0 -307
  265. openapi_schema/rpc_schema.py +0 -416
  266. validators/__init__.py +0 -14
  267. validators/base_validator.py +0 -23
  268. validators/docstring_validator.py +0 -75
  269. validators/metadata_validator.py +0 -76
@@ -0,0 +1,229 @@
1
+ """
2
+ mTLS Proxy for MCP Proxy Adapter
3
+
4
+ This module provides mTLS proxy functionality that accepts mTLS connections
5
+ and proxies them to the internal hypercorn server.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import asyncio
12
+ import ssl
13
+ import logging
14
+ from typing import Optional, Dict, Any
15
+
16
+ from .logging import get_global_logger
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class MTLSProxy:
22
+ """
23
+ mTLS Proxy that accepts mTLS connections and proxies them to internal server.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ external_host: str,
29
+ external_port: int,
30
+ internal_host: str = "127.0.0.1",
31
+ internal_port: int = 9000,
32
+ cert_file: Optional[str] = None,
33
+ key_file: Optional[str] = None,
34
+ ca_cert: Optional[str] = None,
35
+ ):
36
+ """
37
+ Initialize mTLS Proxy.
38
+
39
+ Args:
40
+ external_host: External host to bind to
41
+ external_port: External port to bind to
42
+ internal_host: Internal server host
43
+ internal_port: Internal server port
44
+ cert_file: Server certificate file
45
+ key_file: Server private key file
46
+ ca_cert: CA certificate file for client verification
47
+ """
48
+ self.external_host = external_host
49
+ self.external_port = external_port
50
+ self.internal_host = internal_host
51
+ self.internal_port = internal_port
52
+ self.cert_file = cert_file
53
+ self.key_file = key_file
54
+ self.ca_cert = ca_cert
55
+ self.server = None
56
+
57
+ async def start(self):
58
+ """Start the mTLS proxy server."""
59
+ try:
60
+ # Create SSL context
61
+ ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
62
+ ssl_context.load_cert_chain(self.cert_file, self.key_file)
63
+
64
+ if self.ca_cert:
65
+ ssl_context.load_verify_locations(self.ca_cert)
66
+ ssl_context.verify_mode = ssl.CERT_REQUIRED
67
+ else:
68
+ ssl_context.verify_mode = ssl.CERT_NONE
69
+
70
+ # Start server
71
+ self.server = await asyncio.start_server(
72
+ self._handle_client,
73
+ self.external_host,
74
+ self.external_port,
75
+ ssl=ssl_context,
76
+ )
77
+
78
+ get_global_logger().info(
79
+ f"🔐 mTLS Proxy started on {self.external_host}:{self.external_port}"
80
+ )
81
+ get_global_logger().info(
82
+ f"🌐 Proxying to {self.internal_host}:{self.internal_port}"
83
+ )
84
+
85
+ except Exception as e:
86
+ get_global_logger().error(f"❌ Failed to start mTLS proxy: {e}")
87
+ raise
88
+
89
+ async def _proxy_data(self, reader, writer, direction):
90
+ """Proxy data between reader and writer."""
91
+ try:
92
+ while True:
93
+ data = await reader.read(4096)
94
+ if not data:
95
+ break
96
+ writer.write(data)
97
+ await writer.drain()
98
+ except Exception as e:
99
+ get_global_logger().debug(f"Proxy connection closed ({direction}): {e}")
100
+ finally:
101
+ try:
102
+ writer.close()
103
+ await writer.wait_closed()
104
+ except Exception:
105
+ pass
106
+
107
+ async def _handle_client(self, reader, writer):
108
+ """
109
+ Handle incoming client connection.
110
+
111
+ Args:
112
+ reader: Client reader stream
113
+ writer: Client writer stream
114
+ """
115
+ internal_reader = None
116
+ internal_writer = None
117
+
118
+ try:
119
+ # Connect to internal server
120
+ internal_reader, internal_writer = await asyncio.open_connection(
121
+ self.internal_host, self.internal_port
122
+ )
123
+
124
+ # Create bidirectional proxy tasks
125
+ client_to_server = asyncio.create_task(
126
+ self._proxy_data(reader, internal_writer, "client->server")
127
+ )
128
+ server_to_client = asyncio.create_task(
129
+ self._proxy_data(internal_reader, writer, "server->client")
130
+ )
131
+
132
+ # Wait for either direction to complete
133
+ done, pending = await asyncio.wait(
134
+ [client_to_server, server_to_client],
135
+ return_when=asyncio.FIRST_COMPLETED,
136
+ )
137
+
138
+ # Cancel pending tasks
139
+ for task in pending:
140
+ task.cancel()
141
+
142
+ # Wait for cancellation
143
+ await asyncio.gather(*pending, return_exceptions=True)
144
+
145
+ except Exception as e:
146
+ get_global_logger().debug(f"Client connection error: {e}")
147
+ finally:
148
+ # Clean up connections
149
+ if internal_writer:
150
+ try:
151
+ internal_writer.close()
152
+ await internal_writer.wait_closed()
153
+ except Exception:
154
+ pass
155
+ if writer:
156
+ try:
157
+ writer.close()
158
+ await writer.wait_closed()
159
+ except Exception:
160
+ pass
161
+
162
+
163
+ async def start_mtls_proxy(
164
+ config: Dict[str, Any], internal_port: Optional[int] = None
165
+ ) -> Optional[MTLSProxy]:
166
+ """
167
+ Start mTLS proxy from configuration.
168
+
169
+ Args:
170
+ config: Configuration dictionary
171
+ internal_port: Internal server port (hypercorn port). If not provided,
172
+ will be calculated as external_port + 1000
173
+
174
+ Returns:
175
+ MTLSProxy instance if started successfully, None otherwise
176
+ """
177
+ try:
178
+ server_config = config.get("server", {})
179
+ transport_config = config.get("transport", {})
180
+ ssl_config = config.get("ssl", {})
181
+
182
+ # Get external host and port
183
+ external_host = server_config.get("host", "0.0.0.0")
184
+ external_port = server_config.get("port", 8001)
185
+
186
+ # Get internal port (use provided or calculate)
187
+ if internal_port is None:
188
+ internal_port = external_port + 1000
189
+
190
+ # Get certificate paths - try multiple locations
191
+ cert_file = (
192
+ ssl_config.get("cert_file")
193
+ or transport_config.get("ssl", {}).get("cert_file")
194
+ or transport_config.get("cert_file")
195
+ )
196
+ key_file = (
197
+ ssl_config.get("key_file")
198
+ or transport_config.get("ssl", {}).get("key_file")
199
+ or transport_config.get("key_file")
200
+ )
201
+ ca_cert = (
202
+ ssl_config.get("ca_cert")
203
+ or transport_config.get("ssl", {}).get("ca_cert")
204
+ or transport_config.get("ca_cert")
205
+ )
206
+
207
+ if not cert_file or not key_file:
208
+ get_global_logger().warning(
209
+ "mTLS certificates not found, skipping mTLS proxy"
210
+ )
211
+ return None
212
+
213
+ # Create and start proxy
214
+ proxy = MTLSProxy(
215
+ external_host=external_host,
216
+ external_port=external_port,
217
+ internal_host="127.0.0.1",
218
+ internal_port=internal_port,
219
+ cert_file=cert_file,
220
+ key_file=key_file,
221
+ ca_cert=ca_cert,
222
+ )
223
+
224
+ await proxy.start()
225
+ return proxy
226
+
227
+ except Exception as e:
228
+ get_global_logger().error(f"Failed to start mTLS proxy: {e}")
229
+ return None
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ mTLS Server implementation using built-in http.server.
4
+
5
+ Author: Vasiliy Zdanovskiy
6
+ email: vasilyvz@gmail.com
7
+ """
8
+
9
+ import threading
10
+ import ssl
11
+ import json
12
+ import logging
13
+ from http.server import HTTPServer, BaseHTTPRequestHandler
14
+ from typing import Optional, Dict, Any
15
+ import os
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ class mTLSHandler(BaseHTTPRequestHandler):
21
+ """Handler for mTLS connections."""
22
+
23
+ def __init__(self, *args, main_app=None, **kwargs):
24
+ self.main_app = main_app
25
+ super().__init__(*args, **kwargs)
26
+
27
+
28
+
29
+
30
+ def _forward_to_main_app(
31
+ self,
32
+ method: str,
33
+ path: str,
34
+ client_cert: Optional[Dict],
35
+ post_data: Optional[bytes] = None,
36
+ ) -> Dict[str, Any]:
37
+ """Forward request to main FastAPI application."""
38
+ try:
39
+ # This is a simplified forwarding - in real implementation
40
+ # you would use httpx or similar to make internal HTTP calls
41
+ # to the main FastAPI app running on different port
42
+
43
+ return {
44
+ "status": "ok",
45
+ "message": f"mTLS {method} forwarded to main app",
46
+ "client_cert": client_cert,
47
+ "path": path,
48
+ "forwarded": True,
49
+ }
50
+ except Exception as e:
51
+ get_global_logger().error(f"Error forwarding to main app: {e}")
52
+ return {
53
+ "status": "error",
54
+ "message": f"Forwarding failed: {e}",
55
+ "client_cert": client_cert,
56
+ "path": path,
57
+ }
58
+
59
+
60
+ class mTLSServer:
61
+ """mTLS Server using built-in http.server."""
62
+
63
+ def __init__(
64
+ self,
65
+ host: str = "127.0.0.1",
66
+ port: int = 8443,
67
+ cert_file: str = None,
68
+ key_file: str = None,
69
+ ca_cert_file: str = None,
70
+ main_app=None,
71
+ ):
72
+ """
73
+ Initialize mTLS server.
74
+
75
+ Args:
76
+ host: Server host
77
+ port: Server port
78
+ cert_file: Server certificate file
79
+ key_file: Server private key file
80
+ ca_cert_file: CA certificate file for client verification
81
+ main_app: Main FastAPI application for forwarding requests
82
+ """
83
+ self.host = host
84
+ self.port = port
85
+ self.cert_file = cert_file
86
+ self.key_file = key_file
87
+ self.ca_cert_file = ca_cert_file
88
+ self.main_app = main_app
89
+
90
+ self.server: Optional[HTTPServer] = None
91
+ self.server_thread: Optional[threading.Thread] = None
92
+ self.running = False
93
+
94
+ get_global_logger().info(f"mTLS Server initialized: {host}:{port}")
95
+
96
+ def _create_handler(self):
97
+ """Create handler with main app reference."""
98
+
99
+
100
+ return handler
101
+
102
+ def start(self) -> bool:
103
+ """Start mTLS server in separate thread."""
104
+ try:
105
+ # Check if certificate files exist
106
+ if not os.path.exists(self.cert_file):
107
+ get_global_logger().error(f"Certificate file not found: {self.cert_file}")
108
+ return False
109
+
110
+ if not os.path.exists(self.key_file):
111
+ get_global_logger().error(f"Key file not found: {self.key_file}")
112
+ return False
113
+
114
+ if not os.path.exists(self.ca_cert_file):
115
+ get_global_logger().error(
116
+ f"CA certificate file not found: {self.ca_cert_file}"
117
+ )
118
+ return False
119
+
120
+ # Create server
121
+ handler_class = self._create_handler()
122
+ self.server = HTTPServer((self.host, self.port), handler_class)
123
+
124
+ # Configure SSL context
125
+ context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
126
+ context.load_cert_chain(self.cert_file, self.key_file)
127
+ context.load_verify_locations(self.ca_cert_file)
128
+ context.verify_mode = ssl.CERT_REQUIRED
129
+
130
+ # Wrap socket with SSL
131
+ self.server.socket = context.wrap_socket(
132
+ self.server.socket, server_side=True
133
+ )
134
+
135
+ # Start server in separate thread
136
+ self.server_thread = threading.Thread(
137
+ target=self._run_server, daemon=True
138
+ )
139
+ self.server_thread.start()
140
+
141
+ self.running = True
142
+ get_global_logger().info(
143
+ f"✅ mTLS Server started on https://{self.host}:{self.port}"
144
+ )
145
+ return True
146
+
147
+ except Exception as e:
148
+ get_global_logger().error(f"Failed to start mTLS server: {e}")
149
+ return False
150
+
151
+
152
+
153
+
154
+
@@ -0,0 +1,232 @@
1
+ """
2
+ Protocol management module for MCP Proxy Adapter.
3
+
4
+ This module provides functionality for managing and validating protocol configurations,
5
+ including HTTP, HTTPS, and MTLS protocols with their respective ports.
6
+ """
7
+
8
+ import ssl
9
+ from urllib.parse import urlparse
10
+ from typing import Dict, List, Any, Optional
11
+
12
+ from mcp_proxy_adapter.config import config
13
+ from mcp_proxy_adapter.core.logging import get_global_logger
14
+
15
+
16
+ class ProtocolManager:
17
+ """
18
+ Manages protocol configurations and validates protocol access.
19
+
20
+ This class handles the validation of allowed protocols and their associated ports,
21
+ ensuring that only configured protocols are accessible.
22
+ """
23
+
24
+ def __init__(self, app_config: Optional[Dict] = None):
25
+ """
26
+ Initialize the protocol manager.
27
+
28
+ Args:
29
+ app_config: Application configuration dictionary (optional)
30
+ """
31
+ self.app_config = app_config
32
+ self._load_config()
33
+
34
+ def _load_config(self):
35
+ """Load protocol configuration from config."""
36
+ # Use provided config or fallback to global config; normalize types
37
+ current_config = (
38
+ self.app_config if self.app_config is not None else config.get_all()
39
+ )
40
+ get_global_logger().debug(
41
+ f"ProtocolManager._load_config - current_config type: {type(current_config)}"
42
+ )
43
+
44
+ if not hasattr(current_config, "get"):
45
+ # Not a dict-like config, fallback to global
46
+ get_global_logger().debug(
47
+ f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config"
48
+ )
49
+ current_config = config.get_all()
50
+
51
+ get_global_logger().debug(
52
+ f"ProtocolManager._load_config - final current_config type: {type(current_config)}"
53
+ )
54
+ if hasattr(current_config, "get"):
55
+ get_global_logger().debug(
56
+ f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}"
57
+ )
58
+
59
+ # Get server protocol configuration (new simplified structure)
60
+ get_global_logger().debug(f"ProtocolManager._load_config - before getting server protocol")
61
+ try:
62
+ server_config = current_config.get("server", {})
63
+ server_protocol = server_config.get("protocol", "http")
64
+ get_global_logger().debug(f"ProtocolManager._load_config - server protocol: {server_protocol}")
65
+
66
+ # Set allowed protocols based on server protocol
67
+ if server_protocol == "http":
68
+ self.allowed_protocols = ["http"]
69
+ elif server_protocol == "https":
70
+ self.allowed_protocols = ["https"]
71
+ elif server_protocol == "mtls":
72
+ self.allowed_protocols = ["mtls", "https"] # mTLS also supports HTTPS
73
+ else:
74
+ # Fallback to HTTP
75
+ self.allowed_protocols = ["http"]
76
+ get_global_logger().warning(f"Unknown server protocol '{server_protocol}', defaulting to HTTP")
77
+
78
+ get_global_logger().debug(f"ProtocolManager._load_config - allowed protocols: {self.allowed_protocols}")
79
+
80
+ except Exception as e:
81
+ get_global_logger().debug(f"ProtocolManager._load_config - ERROR getting server protocol: {e}")
82
+ # Fallback to HTTP
83
+ self.allowed_protocols = ["http"]
84
+
85
+ # Protocol management is always enabled in new structure
86
+ self.enabled = True
87
+
88
+ get_global_logger().debug(
89
+ f"Protocol manager loaded config: enabled={self.enabled}, allowed_protocols={self.allowed_protocols}"
90
+ )
91
+
92
+
93
+
94
+
95
+ def is_protocol_allowed(self, protocol: str) -> bool:
96
+ """
97
+ Check if a protocol is allowed based on configuration.
98
+
99
+ Args:
100
+ protocol: Protocol name (http, https, mtls)
101
+
102
+ Returns:
103
+ True if protocol is allowed, False otherwise
104
+ """
105
+ get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - protocol: {protocol}")
106
+ get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - enabled: {self.enabled}")
107
+ get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - allowed_protocols: {self.allowed_protocols}")
108
+
109
+ if not self.enabled:
110
+ get_global_logger().debug("✅ ProtocolManager.is_protocol_allowed - Protocol management is disabled, allowing all protocols")
111
+ return True
112
+
113
+ protocol_lower = protocol.lower()
114
+ is_allowed = protocol_lower in self.allowed_protocols
115
+
116
+ get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - Protocol '{protocol}' allowed: {is_allowed}")
117
+ return is_allowed
118
+
119
+
120
+
121
+ def get_protocol_config(self, protocol: str) -> Dict:
122
+ """
123
+ Get full configuration for a specific protocol.
124
+
125
+ Args:
126
+ protocol: Protocol name (http, https, mtls)
127
+
128
+ Returns:
129
+ Protocol configuration dictionary
130
+ """
131
+ protocol_lower = protocol.lower()
132
+ cfg = self.protocols_config.get(protocol_lower, {})
133
+ # Ensure dict type
134
+ if isinstance(cfg, dict):
135
+ try:
136
+ return cfg.copy()
137
+ except Exception:
138
+ return {}
139
+ return {}
140
+
141
+
142
+ def get_ssl_context_for_protocol(self, protocol: str) -> Optional[ssl.SSLContext]:
143
+ """
144
+ Get SSL context for HTTPS or MTLS protocol.
145
+
146
+ Args:
147
+ protocol: Protocol name (https, mtls)
148
+
149
+ Returns:
150
+ SSL context if protocol requires SSL, None otherwise
151
+ """
152
+ if protocol.lower() not in ["https", "mtls"]:
153
+ return None
154
+
155
+ # Use provided config or fallback to global config
156
+ current_config = (
157
+ self.app_config if self.app_config is not None else config.get_all()
158
+ )
159
+
160
+ # Get SSL configuration
161
+ ssl_config = self._get_ssl_config(current_config)
162
+
163
+ if not ssl_config.get("enabled", False):
164
+ get_global_logger().warning(
165
+ f"SSL required for protocol '{protocol}' but SSL is disabled"
166
+ )
167
+ return None
168
+
169
+ cert_file = ssl_config.get("cert_file")
170
+ key_file = ssl_config.get("key_file")
171
+
172
+ if not cert_file or not key_file:
173
+ get_global_logger().warning(
174
+ f"SSL required for protocol '{protocol}' but certificate files not configured"
175
+ )
176
+ return None
177
+
178
+ try:
179
+ from mcp_proxy_adapter.core.ssl_utils import SSLUtils
180
+
181
+ ssl_context = SSLUtils.create_ssl_context(
182
+ cert_file=cert_file,
183
+ key_file=key_file,
184
+ ca_cert=ssl_config.get("ca_cert"),
185
+ verify_client=protocol.lower() == "mtls"
186
+ or ssl_config.get("verify_client", False),
187
+ cipher_suites=ssl_config.get("cipher_suites", []),
188
+ min_tls_version=ssl_config.get("min_tls_version", "1.2"),
189
+ max_tls_version=ssl_config.get("max_tls_version", "1.3"),
190
+ )
191
+
192
+ get_global_logger().info(f"SSL context created for protocol '{protocol}'")
193
+ return ssl_context
194
+
195
+ except Exception as e:
196
+ get_global_logger().error(f"Failed to create SSL context for protocol '{protocol}': {e}")
197
+ return None
198
+
199
+ def _get_ssl_config(self, current_config: Dict) -> Dict:
200
+ """
201
+ Get SSL configuration from config.
202
+
203
+ Args:
204
+ current_config: Current configuration dictionary
205
+
206
+ Returns:
207
+ SSL configuration dictionary
208
+ """
209
+ # Try security framework SSL config first
210
+ security_config = current_config.get("security", {})
211
+ ssl_config = security_config.get("ssl", {})
212
+
213
+ if ssl_config.get("enabled", False):
214
+ get_global_logger().debug("Using security.ssl configuration")
215
+ return ssl_config
216
+
217
+ # Fallback to legacy SSL config
218
+ legacy_ssl_config = current_config.get("ssl", {})
219
+ if legacy_ssl_config.get("enabled", False):
220
+ get_global_logger().debug("Using legacy ssl configuration")
221
+ return legacy_ssl_config
222
+
223
+ # Return empty config if SSL is disabled
224
+ return {"enabled": False}
225
+
226
+
227
+
228
+
229
+ # Global protocol manager instance - will be updated with config when needed
230
+ protocol_manager = None
231
+
232
+
@@ -0,0 +1,19 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Proxy registration package for MCP Proxy Adapter.
6
+ """
7
+
8
+ from .proxy_registration_manager import ProxyRegistrationManager, ProxyRegistrationError
9
+ from .auth_manager import AuthManager
10
+ from .ssl_manager import SSLManager
11
+ from .registration_client import RegistrationClient
12
+
13
+ __all__ = [
14
+ "ProxyRegistrationManager",
15
+ "ProxyRegistrationError",
16
+ "AuthManager",
17
+ "SSLManager",
18
+ "RegistrationClient",
19
+ ]
@@ -0,0 +1,26 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Authentication management for proxy registration.
6
+ """
7
+
8
+ from typing import Dict, Any
9
+
10
+ from mcp_proxy_adapter.core.logging import get_global_logger
11
+
12
+
13
+ class AuthManager:
14
+ """Manager for authentication in proxy registration."""
15
+
16
+ def __init__(self, client_security, registration_config: Dict[str, Any]):
17
+ """
18
+ Initialize authentication manager.
19
+
20
+ Args:
21
+ client_security: Client security manager instance
22
+ registration_config: Registration configuration
23
+ """
24
+ self.client_security = client_security
25
+ self.registration_config = registration_config
26
+ self.logger = get_global_logger()