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,92 @@
1
+ """
2
+ Module with unload command implementation.
3
+ """
4
+
5
+ from typing import Dict, Any, Optional, List
6
+
7
+ from mcp_proxy_adapter.commands.base import Command
8
+ from mcp_proxy_adapter.commands.command_registry import registry
9
+
10
+
11
+ class UnloadResult(SuccessResult):
12
+ """
13
+ Result of the unload command execution.
14
+ """
15
+
16
+ def __init__(
17
+ self,
18
+ success: bool,
19
+ command_name: str,
20
+ message: str,
21
+ error: Optional[str] = None,
22
+ ):
23
+ """
24
+ Initialize unload command result.
25
+
26
+ Args:
27
+ success: Whether unloading was successful
28
+ command_name: Name of the command that was unloaded
29
+ message: Result message
30
+ error: Error message if unloading failed
31
+ """
32
+ data = {"success": success, "command_name": command_name}
33
+ if error:
34
+ data["error"] = error
35
+
36
+ super().__init__(data=data, message=message)
37
+
38
+ @classmethod
39
+
40
+
41
+ class UnloadCommand(Command):
42
+ """
43
+ Command that unloads loaded commands from registry.
44
+
45
+ This command allows removal of dynamically loaded commands from the command registry.
46
+ Only commands that were loaded via the 'load' command or from the commands directory
47
+ can be unloaded. Built-in commands and custom commands registered with higher priority
48
+ cannot be unloaded using this command.
49
+
50
+ When a command is unloaded:
51
+ - The command class is removed from the loaded commands registry
52
+ - Any command instances are also removed
53
+ - The command becomes unavailable for execution
54
+ - Built-in and custom commands with the same name remain unaffected
55
+
56
+ This is useful for:
57
+ - Removing outdated or problematic commands
58
+ - Managing memory usage by unloading unused commands
59
+ - Testing different versions of commands
60
+ - Cleaning up temporary commands loaded for testing
61
+
62
+ Note: Unloading a command does not affect other commands and does not require
63
+ a system restart. The command can be reloaded later if needed.
64
+ """
65
+
66
+ name = "unload"
67
+ result_class = UnloadResult
68
+
69
+ async def execute(self, command_name: str, **kwargs) -> UnloadResult:
70
+ """
71
+ Execute unload command.
72
+
73
+ Args:
74
+ command_name: Name of the command to unload
75
+ **kwargs: Additional parameters
76
+
77
+ Returns:
78
+ UnloadResult: Unload command result
79
+ """
80
+ # Unload command from registry
81
+ result = registry.unload_command(command_name)
82
+
83
+ return UnloadResult(
84
+ success=result.get("success", False),
85
+ command_name=result.get("command_name", command_name),
86
+ message=result.get("message", "Unknown result"),
87
+ error=result.get("error"),
88
+ )
89
+
90
+ @classmethod
91
+
92
+ @classmethod
@@ -0,0 +1,32 @@
1
+ """
2
+ Module for microservice configuration management.
3
+
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+
8
+ from typing import Optional
9
+
10
+ from .core.config import Config
11
+
12
+ # Global configuration instance
13
+ _config: Optional[Config] = None
14
+
15
+
16
+ def get_config() -> Config:
17
+ """
18
+ Get the global configuration instance.
19
+
20
+ Returns:
21
+ Configuration instance
22
+ """
23
+ global _config
24
+ if _config is None:
25
+ _config = Config()
26
+ return _config
27
+
28
+
29
+
30
+
31
+ # For backward compatibility
32
+ config = get_config()
@@ -0,0 +1,8 @@
1
+ """
2
+ Core package marker for MCP Proxy Adapter.
3
+
4
+ Intentionally lightweight: avoids importing submodules at package import time
5
+ to prevent heavy side effects and circular imports.
6
+ """
7
+
8
+ __all__ = []
@@ -0,0 +1,560 @@
1
+ """
2
+ Application Factory for MCP Proxy Adapter
3
+
4
+ This module provides a factory function for creating and running MCP Proxy Adapter servers
5
+ with proper configuration validation and initialization.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import sys
12
+ from pathlib import Path
13
+ from typing import Optional, Dict, Any
14
+
15
+ from fastapi import FastAPI
16
+ from mcp_proxy_adapter.api.app import create_app
17
+ from mcp_proxy_adapter.core.logging import setup_logging, get_global_logger
18
+ from mcp_proxy_adapter.config import config
19
+
20
+ # Built-in command registration is temporarily disabled in this startup path
21
+
22
+ logger = get_global_logger()
23
+
24
+
25
+ async def create_and_run_server(
26
+ config_path: Optional[str] = None,
27
+ log_config_path: Optional[str] = None,
28
+ title: str = "MCP Proxy Adapter Server",
29
+ description: str = "Model Context Protocol Proxy Adapter with Security Framework",
30
+ version: str = "1.0.0",
31
+ host: str = "0.0.0.0",
32
+ log_level: str = "info",
33
+ engine: Optional[str] = None,
34
+ ) -> None:
35
+ """
36
+ Create and run MCP Proxy Adapter server with proper validation.
37
+
38
+ This factory function validates all configuration files, sets up logging,
39
+ initializes the application, and starts the server with optimal settings.
40
+
41
+ Args:
42
+ config_path: Path to configuration file (JSON)
43
+ log_config_path: Path to logging configuration file (optional)
44
+ title: Application title for OpenAPI schema
45
+ description: Application description for OpenAPI schema
46
+ version: Application version
47
+ host: Server host address
48
+ port: Server port
49
+ log_level: Logging level
50
+ engine: Specific server engine to use (optional)
51
+
52
+ Raises:
53
+ SystemExit: If configuration validation fails or server cannot start
54
+ """
55
+ print("šŸš€ MCP Proxy Adapter Server Factory")
56
+ print("=" * 60)
57
+ print(f"šŸ“‹ Title: {title}")
58
+ print(f"šŸ“ Description: {description}")
59
+ print(f"šŸ”¢ Version: {version}")
60
+ print(f"🌐 Host: {host}")
61
+ print(f"šŸ“Š Log Level: {log_level}")
62
+ print("=" * 60)
63
+ print()
64
+
65
+ # 1. Validate and load configuration file
66
+ app_config = None
67
+ if config_path:
68
+ config_file = Path(config_path)
69
+ if not config_file.exists():
70
+ print(f"āŒ Configuration file not found: {config_path}")
71
+ print(" Please provide a valid path to config.json")
72
+ sys.exit(1)
73
+
74
+ try:
75
+ from mcp_proxy_adapter.config import Config
76
+
77
+ config_instance = Config(config_path=str(config_file))
78
+ app_config = config_instance.config_data
79
+ print(f"āœ… Configuration loaded from: {config_path}")
80
+
81
+ # Validate UUID configuration (mandatory)
82
+ from mcp_proxy_adapter.core.config_validator import ConfigValidator
83
+
84
+ validator = ConfigValidator()
85
+ validator.config_data = app_config
86
+ validation_results = validator.validate_config()
87
+ errors = [r for r in validation_results if r.level == "error"]
88
+ if errors:
89
+ print("āŒ Configuration validation failed:")
90
+ for error in errors:
91
+ print(f" - {error}")
92
+ sys.exit(1)
93
+ print("āœ… Configuration validation passed")
94
+
95
+ # Debug: Check what config.get_all() actually returns
96
+ print(f"šŸ” Debug: config.get_all() keys: {list(app_config.keys())}")
97
+ if "security" in app_config:
98
+ security_ssl = app_config["security"].get("ssl", {})
99
+ print(f"šŸ” Debug: config.get_all() security.ssl: {security_ssl}")
100
+
101
+ # Debug: Check if root ssl section exists after loading
102
+ if "ssl" in app_config:
103
+ print(
104
+ f"šŸ” Debug: Root SSL section after loading: enabled={app_config['ssl'].get('enabled', False)}"
105
+ )
106
+ print(
107
+ f"šŸ” Debug: Root SSL section after loading: cert_file={app_config['ssl'].get('cert_file')}"
108
+ )
109
+ print(
110
+ f"šŸ” Debug: Root SSL section after loading: key_file={app_config['ssl'].get('key_file')}"
111
+ )
112
+ else:
113
+ print("šŸ” Debug: No root SSL section after loading")
114
+
115
+ # Debug: Check app_config immediately after get_all()
116
+ if app_config and "ssl" in app_config:
117
+ ssl_config = app_config["ssl"]
118
+ print(
119
+ f"šŸ” Debug: app_config after get_all(): SSL enabled={ssl_config.get('enabled', False)}"
120
+ )
121
+ print(
122
+ f"šŸ” Debug: app_config after get_all(): SSL cert_file={ssl_config.get('cert_file')}"
123
+ )
124
+ print(
125
+ f"šŸ” Debug: app_config after get_all(): SSL key_file={ssl_config.get('key_file')}"
126
+ )
127
+
128
+ # CRITICAL: Validate SSL configuration - NO FALLBACKS!
129
+ if app_config and "ssl" in app_config:
130
+ ssl_config = app_config["ssl"]
131
+ ssl_enabled = ssl_config.get("enabled", False)
132
+ protocol = app_config.get("server", {}).get("protocol", "http")
133
+
134
+ print(f"šŸ” Debug: SSL enabled={ssl_enabled}, protocol={protocol}")
135
+
136
+ # CRITICAL CHECK: If SSL is enabled, protocol MUST be https or mtls
137
+ if ssl_enabled and protocol not in ["https", "mtls"]:
138
+ raise ValueError(
139
+ f"CRITICAL CONFIG ERROR: SSL is enabled but protocol is '{protocol}'. "
140
+ f"Protocol MUST be 'https' or 'mtls' when SSL is enabled. "
141
+ f"Fix your configuration file."
142
+ )
143
+
144
+ # CRITICAL CHECK: If protocol is https/mtls, SSL MUST be enabled
145
+ if protocol in ["https", "mtls"] and not ssl_enabled:
146
+ raise ValueError(
147
+ f"CRITICAL CONFIG ERROR: Protocol is '{protocol}' but SSL is disabled. "
148
+ f"SSL MUST be enabled when protocol is 'https' or 'mtls'. "
149
+ f"Fix your configuration file."
150
+ )
151
+
152
+ # CRITICAL CHECK: If SSL is enabled, cert and key files MUST exist
153
+ if ssl_enabled:
154
+ cert_file = ssl_config.get("cert_file")
155
+ key_file = ssl_config.get("key_file")
156
+
157
+ if not cert_file or not key_file:
158
+ raise ValueError(
159
+ f"CRITICAL CONFIG ERROR: SSL is enabled but cert_file or key_file is missing. "
160
+ f"cert_file={cert_file}, key_file={key_file}. "
161
+ f"Fix your configuration file."
162
+ )
163
+
164
+ if not Path(cert_file).exists():
165
+ raise ValueError(
166
+ f"CRITICAL CONFIG ERROR: SSL certificate file does not exist: {cert_file}. "
167
+ f"Fix your configuration file or create the certificate."
168
+ )
169
+
170
+ if not Path(key_file).exists():
171
+ raise ValueError(
172
+ f"CRITICAL CONFIG ERROR: SSL key file does not exist: {key_file}. "
173
+ f"Fix your configuration file or create the key."
174
+ )
175
+
176
+ print(
177
+ f"āœ… SSL configuration validated: cert={cert_file}, key={key_file}"
178
+ )
179
+
180
+ # Validate security framework configuration only if enabled
181
+ security_config = app_config.get("security", {})
182
+ if security_config.get("enabled", False):
183
+ framework = security_config.get("framework", "mcp_security_framework")
184
+ print(f"šŸ”’ Security framework: {framework}")
185
+
186
+ # Debug: Check SSL config before validation
187
+ ssl_config = app_config.get("ssl", {})
188
+ print(
189
+ f"šŸ” Debug: SSL config before validation: enabled={ssl_config.get('enabled', False)}"
190
+ )
191
+
192
+ # Validate security configuration
193
+ from mcp_proxy_adapter.core.unified_config_adapter import (
194
+ UnifiedConfigAdapter,
195
+ )
196
+
197
+ adapter = UnifiedConfigAdapter()
198
+ validation_result = adapter.validate_configuration(app_config)
199
+
200
+ # Debug: Check SSL config after validation
201
+ ssl_config = app_config.get("ssl", {})
202
+ print(
203
+ f"šŸ” Debug: SSL config after validation: enabled={ssl_config.get('enabled', False)}"
204
+ )
205
+
206
+ if not validation_result.is_valid:
207
+ print("āŒ Security configuration validation failed:")
208
+ for error in validation_result.errors:
209
+ print(f" - {error}")
210
+ sys.exit(1)
211
+
212
+ if validation_result.warnings:
213
+ print("āš ļø Security configuration warnings:")
214
+ for warning in validation_result.warnings:
215
+ print(f" - {warning}")
216
+
217
+ print("āœ… Security configuration validated successfully")
218
+ else:
219
+ print("šŸ”“ Security framework disabled")
220
+
221
+ except Exception as e:
222
+ print(f"āŒ Failed to load configuration from {config_path}: {e}")
223
+ sys.exit(1)
224
+ else:
225
+ print("āš ļø No configuration file provided, using defaults")
226
+ app_config = config.config_data
227
+
228
+ # 2. Setup logging
229
+ try:
230
+ if log_config_path:
231
+ log_config_file = Path(log_config_path)
232
+ if not log_config_file.exists():
233
+ print(f"āŒ Log configuration file not found: {log_config_path}")
234
+ sys.exit(1)
235
+ setup_logging(log_config_path=str(log_config_file))
236
+ print(f"āœ… Logging configured from: {log_config_path}")
237
+ else:
238
+ setup_logging()
239
+ print("āœ… Logging configured with defaults")
240
+ except Exception as e:
241
+ print(f"āŒ Failed to setup logging: {e}")
242
+ sys.exit(1)
243
+
244
+ # 3. Register built-in commands (disabled)
245
+ print("āš ļø Built-in command registration disabled for simplified startup")
246
+
247
+ # 4. Create FastAPI application with configuration
248
+ try:
249
+ # Debug: Check app_config before passing to create_app
250
+ if app_config and "security" in app_config:
251
+ ssl_config = app_config["security"].get("ssl", {})
252
+ print(
253
+ f"šŸ” Debug: app_config before create_app: SSL enabled={ssl_config.get('enabled', False)}"
254
+ )
255
+ print(
256
+ f"šŸ” Debug: app_config before create_app: SSL cert_file={ssl_config.get('cert_file')}"
257
+ )
258
+ print(
259
+ f"šŸ” Debug: app_config before create_app: SSL key_file={ssl_config.get('key_file')}"
260
+ )
261
+
262
+ app = create_app(
263
+ title=title,
264
+ description=description,
265
+ version=version,
266
+ app_config=app_config, # Pass configuration to create_app
267
+ config_path=config_path, # Pass config path to preserve SSL settings
268
+ )
269
+ print("āœ… FastAPI application created successfully")
270
+ except Exception as e:
271
+ print(f"āŒ Failed to create FastAPI application: {e}")
272
+ sys.exit(1)
273
+
274
+ # 5. Create server configuration
275
+ # Get port from config if available, otherwise use default
276
+ server_port = app_config.get("server", {}).get("port", 8000) if app_config else 8000
277
+ print(f"šŸ”Œ Port: {server_port}")
278
+
279
+ server_config = {
280
+ "host": host,
281
+ "port": server_port,
282
+ "log_level": log_level,
283
+ "reload": False,
284
+ }
285
+
286
+ # Add SSL configuration if present
287
+ print(
288
+ f"šŸ” Debug: app_config keys: {list(app_config.keys()) if app_config else 'None'}"
289
+ )
290
+
291
+ # Check for SSL config in root ssl section first (new format)
292
+ if app_config and "ssl" in app_config:
293
+ ssl_config = app_config["ssl"]
294
+ print(f"šŸ” Debug: SSL config found in root: {ssl_config}")
295
+ print(f"šŸ” Debug: SSL enabled: {ssl_config.get('enabled', False)}")
296
+ if ssl_config.get("enabled", False):
297
+ # Add SSL config directly to server_config for Hypercorn
298
+ server_config["certfile"] = ssl_config.get("cert_file")
299
+ server_config["keyfile"] = ssl_config.get("key_file")
300
+ server_config["ca_certs"] = ssl_config.get(
301
+ "ca_cert_file", ssl_config.get("ca_cert")
302
+ )
303
+ # Set verify_mode based on verify_client setting
304
+ if ssl_config.get("verify_client", False):
305
+ server_config["verify_mode"] = "CERT_REQUIRED"
306
+ else:
307
+ server_config["verify_mode"] = ssl_config.get("verify_mode")
308
+ print(f"šŸ”’ SSL enabled: {ssl_config.get('cert_file', 'N/A')}")
309
+ print(
310
+ f"šŸ”’ SSL enabled: cert={ssl_config.get('cert_file')}, key={ssl_config.get('key_file')}"
311
+ )
312
+ print(
313
+ f"šŸ”’ Server config SSL: certfile={server_config.get('certfile')}, keyfile={server_config.get('keyfile')}, ca_certs={server_config.get('ca_certs')}, verify_mode={server_config.get('verify_mode')}"
314
+ )
315
+
316
+ # Check for SSL config in security section (fallback)
317
+ if app_config and "security" in app_config:
318
+ security_config = app_config["security"]
319
+ print(f"šŸ” Debug: security_config keys: {list(security_config.keys())}")
320
+ if "ssl" in security_config:
321
+ print(f"šŸ” Debug: SSL config found in security: {security_config['ssl']}")
322
+ print(
323
+ f"šŸ” Debug: SSL enabled: {security_config['ssl'].get('enabled', False)}"
324
+ )
325
+ if security_config["ssl"].get("enabled", False):
326
+ ssl_config = security_config["ssl"]
327
+ # Add SSL config directly to server_config for Hypercorn
328
+ server_config["certfile"] = ssl_config.get("cert_file")
329
+ server_config["keyfile"] = ssl_config.get("key_file")
330
+ server_config["ca_certs"] = ssl_config.get(
331
+ "ca_cert_file", ssl_config.get("ca_cert")
332
+ )
333
+ server_config["verify_mode"] = ssl_config.get("verify_mode")
334
+ print(f"šŸ”’ SSL enabled: {ssl_config.get('cert_file', 'N/A')}")
335
+ print(
336
+ f"šŸ”’ SSL enabled: cert={ssl_config.get('cert_file')}, key={ssl_config.get('key_file')}"
337
+ )
338
+ print(
339
+ f"šŸ”’ Server config SSL: certfile={server_config.get('certfile')}, keyfile={server_config.get('keyfile')}, ca_certs={server_config.get('ca_certs')}, verify_mode={server_config.get('verify_mode')}"
340
+ )
341
+
342
+ # 6. Start mTLS server if needed
343
+ mtls_server = None
344
+ try:
345
+ # Check if mTLS is enabled
346
+ ssl_config = app_config.get("ssl", {}) if app_config else {}
347
+ verify_client = ssl_config.get("verify_client", False)
348
+
349
+ if verify_client:
350
+ print("šŸ” mTLS enabled - starting internal mTLS server...")
351
+ print(" External port: mTLS proxy (hypercorn)")
352
+ print(" Internal port: mTLS server (http.server)")
353
+ from mcp_proxy_adapter.core.mtls_server import (
354
+ start_mtls_server_thread,
355
+ )
356
+
357
+ # Start internal mTLS server in separate thread
358
+ # This server will find available port automatically if needed
359
+ mtls_server = start_mtls_server_thread(app_config, main_app=app)
360
+ if mtls_server:
361
+ print(f"āœ… Internal mTLS server started on port {mtls_server.port}")
362
+ else:
363
+ print(
364
+ "āš ļø Failed to start internal mTLS server, continuing with regular HTTPS"
365
+ )
366
+ else:
367
+ print("šŸ”“ mTLS disabled - using regular HTTPS")
368
+ except Exception as e:
369
+ print(f"āš ļø Error starting mTLS server: {e}")
370
+ print(" Continuing with regular HTTPS server")
371
+
372
+ # 7. Start main server
373
+ try:
374
+ print("šŸš€ Starting main server...")
375
+ print(" Use Ctrl+C to stop the server")
376
+ print("=" * 60)
377
+
378
+ # Port availability is already checked in api/app.py before registration manager starts
379
+
380
+ # Use hypercorn directly
381
+ import hypercorn.asyncio
382
+ import hypercorn.config
383
+
384
+ # import asyncio # Unused import
385
+
386
+ # Configure hypercorn
387
+ config_hypercorn = hypercorn.config.Config()
388
+ config_hypercorn.bind = [f"{server_config['host']}:{server_config['port']}"]
389
+ config_hypercorn.loglevel = server_config.get("log_level", "info")
390
+
391
+ # Add SSL shutdown timeout to prevent SSL shutdown timeout errors
392
+ config_hypercorn.ssl_handshake_timeout = 10.0
393
+ config_hypercorn.keep_alive_timeout = 5.0
394
+
395
+ # Add SSL configuration if present
396
+ if "certfile" in server_config:
397
+ config_hypercorn.certfile = server_config["certfile"]
398
+ if "keyfile" in server_config:
399
+ config_hypercorn.keyfile = server_config["keyfile"]
400
+ if "ca_certs" in server_config:
401
+ config_hypercorn.ca_certs = server_config["ca_certs"]
402
+ if "verify_mode" in server_config and server_config["verify_mode"] is not None:
403
+ import ssl
404
+
405
+ # Use the verify_mode from configuration, default to CERT_NONE
406
+ verify_mode = getattr(ssl, server_config["verify_mode"], ssl.CERT_NONE)
407
+ config_hypercorn.verify_mode = verify_mode
408
+
409
+ # Determine if SSL is enabled
410
+ ssl_enabled = any(key in server_config for key in ["certfile", "keyfile"])
411
+
412
+ if ssl_enabled:
413
+ if verify_client:
414
+ print(
415
+ f"šŸ” Starting external mTLS proxy with hypercorn (internal server on port {mtls_server.port if mtls_server else 'N/A'})..."
416
+ )
417
+ else:
418
+ print("šŸ” Starting HTTPS server with hypercorn...")
419
+ else:
420
+ print("🌐 Starting HTTP server with hypercorn...")
421
+
422
+ # Final port check disabled in this refactor; rely on OS errors
423
+
424
+ # Run the server
425
+ # hypercorn.asyncio.serve() should be run with asyncio.run(), not awaited
426
+ # The function is designed to be the main entry point, not a coroutine to await
427
+ await hypercorn.asyncio.serve(app, config_hypercorn)
428
+
429
+ except KeyboardInterrupt:
430
+ print("\nšŸ›‘ Server stopped by user")
431
+ # Stop internal mTLS server if running
432
+ if mtls_server:
433
+ print("šŸ›‘ Stopping internal mTLS server...")
434
+ mtls_server.stop()
435
+ except OSError as e:
436
+ print(f"\nāŒ Failed to start server: {e}")
437
+ # Stop mTLS server if running
438
+ if mtls_server:
439
+ print("šŸ›‘ Stopping mTLS server...")
440
+ mtls_server.stop()
441
+ import traceback
442
+
443
+ traceback.print_exc()
444
+ sys.exit(1)
445
+ except Exception as e:
446
+ print(f"\nāŒ Failed to start server: {e}")
447
+ # Stop internal mTLS server if running
448
+ if mtls_server:
449
+ print("šŸ›‘ Stopping internal mTLS server...")
450
+ mtls_server.stop()
451
+ import traceback
452
+
453
+ traceback.print_exc()
454
+ sys.exit(1)
455
+
456
+
457
+ def validate_config_file(config_path: str) -> bool:
458
+ """
459
+ Validate configuration file exists and is readable.
460
+
461
+ Args:
462
+ config_path: Path to configuration file
463
+
464
+ Returns:
465
+ True if valid, False otherwise
466
+ """
467
+ try:
468
+ config_file = Path(config_path)
469
+ if not config_file.exists():
470
+ print(f"āŒ Configuration file not found: {config_path}")
471
+ return False
472
+
473
+ # Try to load configuration to validate JSON format
474
+ from mcp_proxy_adapter.config import Config
475
+
476
+ Config(config_path=str(config_file))
477
+ return True
478
+
479
+ except Exception as e:
480
+ print(f"āŒ Configuration file validation failed: {e}")
481
+ return False
482
+
483
+
484
+ def validate_log_config_file(log_config_path: str) -> bool:
485
+ """
486
+ Validate logging configuration file exists and is readable.
487
+
488
+ Args:
489
+ log_config_path: Path to logging configuration file
490
+
491
+ Returns:
492
+ True if valid, False otherwise
493
+ """
494
+ try:
495
+ log_config_file = Path(log_config_path)
496
+ if not log_config_file.exists():
497
+ print(f"āŒ Log configuration file not found: {log_config_path}")
498
+ return False
499
+ return True
500
+
501
+ except Exception as e:
502
+ print(f"āŒ Log configuration file validation failed: {e}")
503
+ return False
504
+
505
+
506
+ def create_application(
507
+ config: Dict[str, Any],
508
+ title: str = "MCP Proxy Adapter",
509
+ description: str = "JSON-RPC API for interacting with MCP Proxy",
510
+ version: str = "1.0.0",
511
+ ) -> FastAPI:
512
+ """
513
+ Creates and configures FastAPI application.
514
+
515
+ Args:
516
+ config: Application configuration dictionary
517
+ title: Application title
518
+ description: Application description
519
+ version: Application version
520
+
521
+ Returns:
522
+ Configured FastAPI application
523
+ """
524
+ from fastapi.middleware.cors import CORSMiddleware
525
+ from mcp_proxy_adapter.api.app import create_app
526
+ from mcp_proxy_adapter.core.logging import setup_logging
527
+ from mcp_proxy_adapter.commands.builtin_commands import (
528
+ register_builtin_commands,
529
+ )
530
+
531
+ # Setup logging
532
+ setup_logging()
533
+
534
+ # Register built-in commands
535
+ register_builtin_commands()
536
+
537
+ # Create FastAPI application using existing create_app function
538
+ app = create_app(
539
+ title=title,
540
+ description=description,
541
+ version=version,
542
+ app_config=config,
543
+ )
544
+
545
+ # Add CORS middleware
546
+ app.add_middleware(
547
+ CORSMiddleware,
548
+ allow_origins=["*"],
549
+ allow_credentials=True,
550
+ allow_methods=["*"],
551
+ allow_headers=["*"],
552
+ )
553
+
554
+ # Add health endpoint
555
+ @app.get("/health")
556
+ async def health_check():
557
+ """Health check endpoint."""
558
+ return {"status": "healthy", "version": version}
559
+
560
+ return app