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,47 @@
1
+ """MCP Proxy API Service package.
2
+
3
+ This package provides a framework for creating JSON-RPC-enabled microservices.
4
+ """
5
+
6
+ from mcp_proxy_adapter.version import __version__
7
+ from mcp_proxy_adapter.api.app import create_app
8
+ from mcp_proxy_adapter.commands.base import Command
9
+ from mcp_proxy_adapter.commands.result import CommandResult, SuccessResult, ErrorResult
10
+ from mcp_proxy_adapter.commands.command_registry import registry
11
+ from mcp_proxy_adapter.core.errors import (
12
+ MicroserviceError,
13
+ CommandError,
14
+ ValidationError,
15
+ InvalidParamsError,
16
+ NotFoundError,
17
+ TimeoutError,
18
+ InternalError,
19
+ )
20
+
21
+ # CLI module
22
+ # Delayed import of CLI to avoid side effects during server startup
23
+ # CLI can be accessed via entrypoint `mcp-proxy-adapter` or `python -m mcp_proxy_adapter`
24
+ try:
25
+ from mcp_proxy_adapter.cli import main as cli_main
26
+ except Exception:
27
+ # Avoid import errors impacting library/server usage
28
+ cli_main = None
29
+
30
+ # Экспортируем основные классы и функции для удобного использования
31
+ __all__ = [
32
+ "__version__",
33
+ "create_app",
34
+ "Command",
35
+ "CommandResult",
36
+ "SuccessResult",
37
+ "ErrorResult",
38
+ "registry",
39
+ "MicroserviceError",
40
+ "CommandError",
41
+ "ValidationError",
42
+ "InvalidParamsError",
43
+ "NotFoundError",
44
+ "TimeoutError",
45
+ "InternalError",
46
+ "cli_main",
47
+ ]
@@ -0,0 +1,13 @@
1
+ """
2
+ MCP Proxy Adapter CLI Entry Point
3
+
4
+ This module allows running the CLI using: python -m mcp_proxy_adapter
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ from .cli.main import main
11
+
12
+ if __name__ == '__main__':
13
+ main()
File without changes
@@ -0,0 +1,66 @@
1
+ """
2
+ Module for FastAPI application setup.
3
+ """
4
+
5
+ from typing import Any, Dict, Optional
6
+
7
+ from fastapi import FastAPI
8
+
9
+ from .core import AppFactory, SSLContextFactory, RegistrationManager, LifespanManager
10
+
11
+
12
+
13
+
14
+ def create_lifespan(config_path: Optional[str] = None, current_config: Optional[Dict[str, Any]] = None):
15
+ """
16
+ Create lifespan manager for the FastAPI application.
17
+
18
+ Args:
19
+ config_path: Path to configuration file (optional)
20
+ current_config: Current configuration data (optional)
21
+
22
+ Returns:
23
+ Lifespan context manager
24
+ """
25
+ lifespan_manager = LifespanManager()
26
+ return lifespan_manager.create_lifespan(config_path, current_config)
27
+
28
+
29
+ def create_ssl_context(
30
+ app_config: Optional[Dict[str, Any]] = None
31
+ ) -> Optional[Any]:
32
+ """
33
+ Create SSL context based on configuration.
34
+
35
+ Args:
36
+ app_config: Application configuration dictionary (optional)
37
+
38
+ Returns:
39
+ SSL context if SSL is enabled and properly configured, None otherwise
40
+ """
41
+ ssl_factory = SSLContextFactory()
42
+ return ssl_factory.create_ssl_context(app_config)
43
+
44
+
45
+ def create_app(
46
+ title: Optional[str] = None,
47
+ description: Optional[str] = None,
48
+ version: Optional[str] = None,
49
+ app_config: Optional[Dict[str, Any]] = None,
50
+ config_path: Optional[str] = None,
51
+ ) -> FastAPI:
52
+ """
53
+ Creates and configures FastAPI application.
54
+
55
+ Args:
56
+ title: Application title (default: "MCP Proxy Adapter")
57
+ description: Application description (default: "JSON-RPC API for interacting with MCP Proxy")
58
+ version: Application version (default: "1.0.0")
59
+ app_config: Application configuration dictionary (optional)
60
+ config_path: Path to configuration file (optional)
61
+
62
+ Returns:
63
+ Configured FastAPI application.
64
+ """
65
+ app_factory = AppFactory()
66
+ return app_factory.create_app(title, description, version, app_config, config_path)
@@ -0,0 +1,18 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Core API utilities for MCP Proxy Adapter.
6
+ """
7
+
8
+ from .app_factory import AppFactory
9
+ from .ssl_context_factory import SSLContextFactory
10
+ from .registration_manager import RegistrationManager
11
+ from .lifespan_manager import LifespanManager
12
+
13
+ __all__ = [
14
+ "AppFactory",
15
+ "SSLContextFactory",
16
+ "RegistrationManager",
17
+ "LifespanManager",
18
+ ]
@@ -0,0 +1,400 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Application factory for MCP Proxy Adapter API.
6
+ """
7
+
8
+ from typing import Any, Dict, List, Optional, Union
9
+
10
+ from fastapi import FastAPI, Body
11
+ from mcp_proxy_adapter.api.handlers import (
12
+ handle_json_rpc,
13
+ handle_batch_json_rpc,
14
+ get_server_health,
15
+ get_commands_list,
16
+ )
17
+
18
+ # from mcp_proxy_adapter.api.middleware import setup_middleware
19
+ try:
20
+ from mcp_proxy_adapter.api.schemas import (
21
+ JsonRpcRequest,
22
+ JsonRpcSuccessResponse,
23
+ JsonRpcErrorResponse,
24
+ HealthResponse,
25
+ CommandListResponse,
26
+ APIToolDescription,
27
+ )
28
+ except Exception:
29
+ # If schemas are unavailable, define minimal type aliases to satisfy annotations
30
+ JsonRpcRequest = Dict[str, Any] # type: ignore
31
+ JsonRpcSuccessResponse = Dict[str, Any] # type: ignore
32
+ JsonRpcErrorResponse = Dict[str, Any] # type: ignore
33
+ HealthResponse = Dict[str, Any] # type: ignore
34
+ CommandListResponse = Dict[str, Any] # type: ignore
35
+ APIToolDescription = Dict[str, Any] # type: ignore
36
+
37
+ try:
38
+ from mcp_proxy_adapter.api.tools import get_tool_description, execute_tool
39
+ except Exception:
40
+ get_tool_description = None
41
+ execute_tool = None
42
+ from mcp_proxy_adapter.core.logging import get_global_logger
43
+ from mcp_proxy_adapter.custom_openapi import custom_openapi_with_fallback
44
+ from .ssl_context_factory import SSLContextFactory
45
+ from .lifespan_manager import LifespanManager
46
+
47
+
48
+ class AppFactory:
49
+ """Factory for creating FastAPI applications."""
50
+
51
+ def __init__(self):
52
+ """Initialize app factory."""
53
+ self.logger = get_global_logger()
54
+ self.ssl_factory = SSLContextFactory()
55
+ self.lifespan_manager = LifespanManager()
56
+
57
+ def create_app(
58
+ self,
59
+ title: Optional[str] = None,
60
+ description: Optional[str] = None,
61
+ version: Optional[str] = None,
62
+ app_config: Optional[Dict[str, Any]] = None,
63
+ config_path: Optional[str] = None,
64
+ ) -> FastAPI:
65
+ """
66
+ Creates and configures FastAPI application.
67
+
68
+ Args:
69
+ title: Application title (default: "MCP Proxy Adapter")
70
+ description: Application description (default: "JSON-RPC API for interacting with MCP Proxy")
71
+ version: Application version (default: "1.0.0")
72
+ app_config: Application configuration dictionary (optional)
73
+ config_path: Path to configuration file (optional)
74
+
75
+ Returns:
76
+ Configured FastAPI application.
77
+
78
+ Raises:
79
+ SystemExit: If authentication is enabled but required files are missing (security issue)
80
+ """
81
+ # Store config_path for certificate validation
82
+ self._config_path = config_path
83
+
84
+ # Use provided configuration or fallback to global config
85
+ if app_config is not None:
86
+ if hasattr(app_config, "get_all"):
87
+ current_config = app_config.get_all()
88
+ elif hasattr(app_config, "keys"):
89
+ current_config = app_config
90
+ else:
91
+ # If app_config is not a dict-like object, use it as is
92
+ current_config = app_config
93
+ else:
94
+ # If no app_config provided, try to get global config
95
+ try:
96
+ from mcp_proxy_adapter.config import get_config
97
+
98
+ current_config = get_config().get_all()
99
+ except Exception:
100
+ # If global config is not available, create empty config
101
+ current_config = {}
102
+
103
+ # Debug: Check what config is passed to create_app
104
+ if app_config:
105
+ if hasattr(app_config, "keys"):
106
+ print(
107
+ f"🔍 Debug: create_app received app_config keys: {list(app_config.keys())}"
108
+ )
109
+ # Debug SSL configuration
110
+ protocol = app_config.get("server", {}).get("protocol", "http")
111
+ verify_client = app_config.get("transport", {}).get(
112
+ "verify_client", False
113
+ )
114
+ ssl_enabled = protocol in ["https", "mtls"] or verify_client
115
+ print(f"🔍 Debug: create_app SSL config: enabled={ssl_enabled}")
116
+ print(f"🔍 Debug: create_app protocol: {protocol}")
117
+ print(f"🔍 Debug: create_app verify_client: {verify_client}")
118
+ else:
119
+ print(
120
+ f"🔍 Debug: create_app received app_config type: {type(app_config)}"
121
+ )
122
+ else:
123
+ print("🔍 Debug: create_app received no app_config, using global config")
124
+
125
+ # Security check: Validate configuration strictly at startup (fail-fast)
126
+ self._validate_configuration(current_config)
127
+
128
+ # Security check: Validate all authentication configurations before startup
129
+ self._validate_security_configuration(current_config)
130
+
131
+ # Security check: Validate certificates at startup (fail-fast)
132
+ self._validate_certificates(current_config)
133
+
134
+ # Set default values
135
+ title = title or "MCP Proxy Adapter"
136
+ description = description or "JSON-RPC API for interacting with MCP Proxy"
137
+ version = version or "1.0.0"
138
+
139
+ # Create lifespan manager
140
+ lifespan = self.lifespan_manager.create_lifespan(config_path, current_config)
141
+
142
+ # Create FastAPI application
143
+ app = FastAPI(
144
+ title=title,
145
+ description=description,
146
+ version=version,
147
+ lifespan=lifespan,
148
+ )
149
+
150
+ # Setup middleware - disabled for now
151
+ # setup_middleware(app, current_config)
152
+
153
+ # Setup routes
154
+ self._setup_routes(app)
155
+
156
+ # Setup OpenAPI
157
+ app.openapi = lambda: custom_openapi_with_fallback(app)
158
+
159
+ return app
160
+
161
+ def _validate_configuration(self, current_config: Dict[str, Any]) -> None:
162
+ """Validate configuration at startup."""
163
+ try:
164
+ from mcp_proxy_adapter.core.validation.config_validator import (
165
+ ConfigValidator,
166
+ )
167
+
168
+ validator = ConfigValidator()
169
+ validator.config_data = current_config
170
+ validation_results = validator.validate_config()
171
+ errors = [r for r in validation_results if r.level == "error"]
172
+ warnings = [r for r in validation_results if r.level == "warning"]
173
+
174
+ if errors:
175
+ self.logger.critical(
176
+ "CRITICAL CONFIG ERROR: Invalid configuration at startup:"
177
+ )
178
+ for error in errors:
179
+ self.logger.critical(f" - {error.message}")
180
+ raise SystemExit(1)
181
+ for warning in warnings:
182
+ self.logger.warning(f"Config warning: {warning.message}")
183
+ except Exception as ex:
184
+ self.logger.error(f"Failed to run startup configuration validation: {ex}")
185
+
186
+ def _validate_security_configuration(self, current_config: Dict[str, Any]) -> None:
187
+ """Validate security configuration at startup."""
188
+ security_errors = []
189
+
190
+ print(f"🔍 Debug: current_config keys: {list(current_config.keys())}")
191
+ if "security" in current_config:
192
+ print(f"🔍 Debug: security config: {current_config['security']}")
193
+ if "roles" in current_config:
194
+ print(f"🔍 Debug: roles config: {current_config['roles']}")
195
+
196
+ # Check security framework configuration only if enabled
197
+ security_config = current_config.get("security", {})
198
+ if security_config.get("enabled", False):
199
+ # Validate security framework configuration
200
+ from mcp_proxy_adapter.core.unified_config_adapter import (
201
+ UnifiedConfigAdapter,
202
+ )
203
+
204
+ adapter = UnifiedConfigAdapter()
205
+ validation_result = adapter.validate_configuration(current_config)
206
+
207
+ if not validation_result.is_valid:
208
+ security_errors.extend(validation_result.errors)
209
+
210
+ # Check roles configuration only if enabled
211
+ # Roles validation is handled by UnifiedConfigAdapter in security section validation
212
+ # No need for separate validation here
213
+
214
+ # Fail if there are security errors
215
+ if security_errors:
216
+ self.logger.critical(
217
+ "CRITICAL SECURITY ERROR: Invalid security configuration at startup:"
218
+ )
219
+ for error in security_errors:
220
+ self.logger.critical(f" - {error}")
221
+ raise SystemExit(1)
222
+
223
+ def _validate_certificates(self, current_config: Dict[str, Any]) -> None:
224
+ """
225
+ Validate certificates at startup.
226
+
227
+ Checks:
228
+ - Certificate-key match
229
+ - Certificate expiry
230
+ - Certificate chain (with provided CA or system CA store)
231
+
232
+ Raises SystemExit(1) if validation fails.
233
+ """
234
+ try:
235
+ from mcp_proxy_adapter.core.certificate.certificate_validator import (
236
+ CertificateValidator,
237
+ )
238
+ import os
239
+
240
+ certificate_errors = []
241
+
242
+ # Check if this is SimpleConfig format (support both old and new structure)
243
+ is_simple_config = (
244
+ "server" in current_config
245
+ and (
246
+ "proxy_client" in current_config
247
+ or "client" in current_config
248
+ or "registration" in current_config
249
+ )
250
+ )
251
+
252
+ if is_simple_config:
253
+ # SimpleConfig format
254
+ from mcp_proxy_adapter.core.config.simple_config import (
255
+ SimpleConfigModel,
256
+ ServerConfig,
257
+ ClientConfig,
258
+ RegistrationConfig,
259
+ AuthConfig,
260
+ )
261
+ from mcp_proxy_adapter.core.config.simple_config_validator import (
262
+ SimpleConfigValidator,
263
+ )
264
+
265
+ try:
266
+ # Try to load as SimpleConfig - use SimpleConfig.load() for proper migration
267
+ from mcp_proxy_adapter.core.config.simple_config import SimpleConfig
268
+ from pathlib import Path
269
+
270
+ # If config_path is available, use it
271
+ if hasattr(self, '_config_path') and self._config_path:
272
+ cfg = SimpleConfig(self._config_path)
273
+ model = cfg.load()
274
+ else:
275
+ # Fallback: manual construction with migration support
276
+ server_config = current_config.get("server", {})
277
+ # Filter unknown fields
278
+ known_server_fields = {
279
+ "host", "port", "protocol", "cert_file", "key_file",
280
+ "ca_cert_file", "crl_file", "use_system_ca", "log_dir"
281
+ }
282
+ server_data = {k: v for k, v in server_config.items() if k in known_server_fields}
283
+ server = ServerConfig(**server_data) # type: ignore[arg-type]
284
+
285
+ # Load client config (new format)
286
+ client_config = current_config.get("client", {})
287
+ client = ClientConfig(**client_config) # type: ignore[arg-type]
288
+
289
+ # Load registration config (new format or migrate from proxy_client)
290
+ registration_config = current_config.get("registration", {})
291
+ if not registration_config and current_config.get("proxy_client"):
292
+ # Migrate from old proxy_client format
293
+ pc = current_config.get("proxy_client", {})
294
+ registration_config = {
295
+ "enabled": pc.get("enabled", False),
296
+ "host": pc.get("host", "localhost"),
297
+ "port": pc.get("port", 3005),
298
+ "protocol": pc.get("protocol", "http"),
299
+ "server_id": pc.get("server_id"),
300
+ "server_name": pc.get("server_name"),
301
+ "cert_file": pc.get("cert_file"),
302
+ "key_file": pc.get("key_file"),
303
+ "ca_cert_file": pc.get("ca_cert_file"),
304
+ "crl_file": pc.get("crl_file"),
305
+ "use_system_ca": pc.get("use_system_ca", False),
306
+ "register_endpoint": pc.get("registration", {}).get("register_endpoint", "/register") if isinstance(pc.get("registration"), dict) else "/register",
307
+ "unregister_endpoint": pc.get("registration", {}).get("unregister_endpoint", "/unregister") if isinstance(pc.get("registration"), dict) else "/unregister",
308
+ "auto_on_startup": pc.get("registration", {}).get("auto_on_startup", True) if isinstance(pc.get("registration"), dict) else True,
309
+ "auto_on_shutdown": pc.get("registration", {}).get("auto_on_shutdown", True) if isinstance(pc.get("registration"), dict) else True,
310
+ "heartbeat": pc.get("heartbeat", {}),
311
+ }
312
+
313
+ registration = RegistrationConfig(**registration_config) # type: ignore[arg-type]
314
+ # Handle nested heartbeat
315
+ if isinstance(registration_config.get("heartbeat"), dict):
316
+ from mcp_proxy_adapter.core.config.simple_config import (
317
+ HeartbeatConfig,
318
+ )
319
+ registration.heartbeat = HeartbeatConfig(**registration_config["heartbeat"]) # type: ignore[arg-type]
320
+
321
+ auth_config = current_config.get("auth", {})
322
+ auth = AuthConfig(**auth_config) # type: ignore[arg-type]
323
+
324
+ model = SimpleConfigModel(
325
+ server=server, client=client, registration=registration, auth=auth
326
+ )
327
+
328
+ validator = SimpleConfigValidator()
329
+ validation_errors = validator.validate(model)
330
+
331
+ if validation_errors:
332
+ for error in validation_errors:
333
+ certificate_errors.append(error.message)
334
+
335
+ except Exception as e:
336
+ self.logger.error(
337
+ f"Failed to validate as SimpleConfig format: {e}"
338
+ )
339
+ certificate_errors.append(
340
+ f"Configuration validation failed: {e}. Only SimpleConfig format is supported."
341
+ )
342
+
343
+ # Fail if there are certificate errors
344
+ if certificate_errors:
345
+ self.logger.critical(
346
+ "CRITICAL CERTIFICATE ERROR: Certificate validation failed at startup:"
347
+ )
348
+ for error in certificate_errors:
349
+ self.logger.critical(f" - {error}")
350
+ self.logger.critical(
351
+ "Server startup aborted due to certificate validation errors"
352
+ )
353
+ raise SystemExit(1)
354
+
355
+ except SystemExit:
356
+ raise
357
+ except Exception as ex:
358
+ self.logger.error(f"Failed to run certificate validation: {ex}")
359
+ # Don't fail startup if validation itself fails, but log the error
360
+ self.logger.warning(
361
+ "Certificate validation could not be completed, but server will continue to start"
362
+ )
363
+
364
+ def _setup_routes(self, app: FastAPI) -> None:
365
+ """Setup application routes."""
366
+
367
+ @app.get("/health", response_model=HealthResponse)
368
+ async def health(): # type: ignore
369
+ return await get_server_health() # type: ignore[misc]
370
+
371
+ @app.get("/commands", response_model=CommandListResponse)
372
+ async def commands(): # type: ignore
373
+ return await get_commands_list() # type: ignore[misc]
374
+
375
+ @app.post(
376
+ "/api/jsonrpc",
377
+ response_model=Union[JsonRpcSuccessResponse, JsonRpcErrorResponse],
378
+ )
379
+ async def jsonrpc(request: JsonRpcRequest): # type: ignore
380
+ return await handle_json_rpc(request.dict()) # type: ignore[misc]
381
+
382
+ @app.post(
383
+ "/api/jsonrpc/batch",
384
+ response_model=List[Union[JsonRpcSuccessResponse, JsonRpcErrorResponse]],
385
+ )
386
+ async def jsonrpc_batch(requests: List[JsonRpcRequest]): # type: ignore
387
+ return await handle_batch_json_rpc([req.dict() for req in requests]) # type: ignore[misc]
388
+
389
+ # Optional tool endpoints if tools module is available
390
+ if get_tool_description and execute_tool:
391
+
392
+ @app.get("/api/tools", response_model=List[APIToolDescription])
393
+ async def tools(): # type: ignore
394
+ return await get_tool_description() # type: ignore[misc]
395
+
396
+ @app.post("/api/tools/{tool_name}")
397
+ async def execute_tool_endpoint(
398
+ tool_name: str, params: Dict[str, Any] = Body(...)
399
+ ):
400
+ return await execute_tool(tool_name, params) # type: ignore[misc]
@@ -0,0 +1,55 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Lifespan management utilities for MCP Proxy Adapter API.
6
+ """
7
+
8
+ import asyncio
9
+ from contextlib import asynccontextmanager
10
+ from typing import Any, Dict, Optional
11
+
12
+ from fastapi import FastAPI
13
+
14
+ from mcp_proxy_adapter.core.logging import get_global_logger
15
+ from .registration_manager import RegistrationManager
16
+
17
+
18
+ class LifespanManager:
19
+ """Manager for application lifespan events."""
20
+
21
+ def __init__(self):
22
+ """Initialize lifespan manager."""
23
+ self.logger = get_global_logger()
24
+ self.registration_manager = RegistrationManager()
25
+
26
+ def create_lifespan(self, config_path: Optional[str] = None, current_config: Optional[Dict[str, Any]] = None):
27
+ """
28
+ Create lifespan manager for the FastAPI application.
29
+
30
+ Args:
31
+ config_path: Path to configuration file (optional)
32
+ current_config: Current configuration data (optional)
33
+
34
+ Returns:
35
+ Lifespan context manager
36
+ """
37
+
38
+ @asynccontextmanager
39
+ async def lifespan(app: FastAPI):
40
+ """Lifespan context manager."""
41
+ # Startup
42
+ get_global_logger().info("Starting MCP Proxy Adapter")
43
+
44
+ # Register with proxy if configured
45
+ if current_config:
46
+ await self.registration_manager.register_with_proxy(current_config)
47
+ await self.registration_manager.start_heartbeat(current_config)
48
+
49
+ yield
50
+
51
+ # Shutdown
52
+ get_global_logger().info("Shutting down MCP Proxy Adapter")
53
+ await self.registration_manager.stop()
54
+
55
+ return lifespan