mcp-proxy-adapter 6.9.43__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) 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 +355 -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 +266 -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 +35 -0
  36. mcp_proxy_adapter/cli/commands/config_validate.py +74 -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 +128 -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 +388 -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 +116 -0
  119. mcp_proxy_adapter/core/config/simple_config_generator.py +100 -0
  120. mcp_proxy_adapter/core/config/simple_config_validator.py +380 -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 +190 -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 +13 -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 +264 -0
  185. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +81 -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 +313 -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.43.dist-info/METADATA +739 -0
  239. mcp_proxy_adapter-6.9.43.dist-info/RECORD +242 -0
  240. mcp_proxy_adapter-6.9.43.dist-info/WHEEL +5 -0
  241. mcp_proxy_adapter-6.9.43.dist-info/entry_points.txt +12 -0
  242. mcp_proxy_adapter-6.9.43.dist-info/top_level.txt +1 -0
@@ -0,0 +1,52 @@
1
+ """
2
+ Dynamic Calculator Command
3
+ This module demonstrates a dynamically loaded command implementation for the full application example.
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+
8
+ from mcp_proxy_adapter.commands.base import BaseCommand
9
+ from mcp_proxy_adapter.commands.result import CommandResult
10
+
11
+
12
+ class CalculatorResult(CommandResult):
13
+ """Result class for calculator command."""
14
+
15
+ def __init__(self, operation: str, result: float, expression: str):
16
+ self.operation = operation
17
+ self.result = result
18
+ self.expression = expression
19
+
20
+
21
+
22
+
23
+ class DynamicCalculatorCommand(BaseCommand):
24
+ """Dynamic calculator command implementation."""
25
+
26
+
27
+
28
+
29
+ async def execute(self, params: Dict[str, Any]) -> CalculatorResult:
30
+ """Execute the calculator command."""
31
+ operation = params.get("operation")
32
+ a = params.get("a")
33
+ b = params.get("b")
34
+ if operation == "add":
35
+ result = a + b
36
+ expression = f"{a} + {b}"
37
+ elif operation == "subtract":
38
+ result = a - b
39
+ expression = f"{a} - {b}"
40
+ elif operation == "multiply":
41
+ result = a * b
42
+ expression = f"{a} * {b}"
43
+ elif operation == "divide":
44
+ if b == 0:
45
+ raise ValueError("Division by zero is not allowed")
46
+ result = a / b
47
+ expression = f"{a} / {b}"
48
+ else:
49
+ raise ValueError(f"Unknown operation: {operation}")
50
+ return CalculatorResult(
51
+ operation=operation, result=result, expression=expression
52
+ )
@@ -0,0 +1,32 @@
1
+ """
2
+ Echo command implementation.
3
+ """
4
+ from mcp_proxy_adapter.commands.base import BaseCommand
5
+ from mcp_proxy_adapter.core.errors import MicroserviceError
6
+
7
+
8
+ class EchoCommand(BaseCommand):
9
+ """Echo command that returns the input message."""
10
+
11
+ def __init__(self):
12
+ super().__init__()
13
+ self.name = "echo"
14
+ self.description = "Echo command that returns the input message"
15
+ self.version = "1.0.0"
16
+
17
+
18
+ async def execute(self, params: dict) -> dict:
19
+ """Execute echo command."""
20
+ try:
21
+ message = params.get("message", "")
22
+ return {
23
+ "echo": message,
24
+ "timestamp": self._get_timestamp()
25
+ }
26
+ except Exception as e:
27
+ raise MicroserviceError(f"Echo command failed: {str(e)}")
28
+
29
+ def _get_timestamp(self):
30
+ """Get current timestamp."""
31
+ import time
32
+ return time.time()
@@ -0,0 +1,54 @@
1
+ """
2
+ Help command implementation.
3
+ """
4
+ from mcp_proxy_adapter.commands.base import BaseCommand
5
+ from mcp_proxy_adapter.core.errors import MicroserviceError
6
+
7
+
8
+ class HelpCommand(BaseCommand):
9
+ """Help command that provides usage information."""
10
+
11
+ def __init__(self):
12
+ super().__init__()
13
+ self.name = "help"
14
+ self.description = "Get help information"
15
+ self.version = "1.0.0"
16
+
17
+
18
+ async def execute(self, params: dict) -> dict:
19
+ """Execute help command."""
20
+ try:
21
+ command = params.get("command")
22
+
23
+ if command:
24
+ # Get help for specific command
25
+ help_info = self._get_command_help(command)
26
+ return {
27
+ "command": command,
28
+ "help": help_info,
29
+ "timestamp": self._get_timestamp()
30
+ }
31
+ else:
32
+ # Get general help
33
+ return {
34
+ "help": "MCP Proxy Adapter - Available commands: echo, list, health, help",
35
+ "usage": "Use 'help' with a command name to get specific help",
36
+ "timestamp": self._get_timestamp()
37
+ }
38
+ except Exception as e:
39
+ raise MicroserviceError(f"Help command failed: {str(e)}")
40
+
41
+ def _get_command_help(self, command: str) -> str:
42
+ """Get help for specific command."""
43
+ help_map = {
44
+ "echo": "Echo command - returns the input message. Usage: {'message': 'your message'}",
45
+ "list": "List command - returns available commands. Usage: {}",
46
+ "health": "Health command - returns server health status. Usage: {}",
47
+ "help": "Help command - provides usage information. Usage: {'command': 'command_name'} (optional)"
48
+ }
49
+ return help_map.get(command, f"No help available for command '{command}'")
50
+
51
+ def _get_timestamp(self):
52
+ """Get current timestamp."""
53
+ import time
54
+ return time.time()
@@ -0,0 +1,57 @@
1
+ """
2
+ List command implementation.
3
+ """
4
+ from mcp_proxy_adapter.commands.base import BaseCommand
5
+ from mcp_proxy_adapter.core.errors import MicroserviceError
6
+
7
+
8
+ class ListCommand(BaseCommand):
9
+ """List command that returns available commands."""
10
+
11
+ def __init__(self):
12
+ super().__init__()
13
+ self.name = "list"
14
+ self.description = "List available commands"
15
+ self.version = "1.0.0"
16
+
17
+
18
+ async def execute(self, params: dict) -> dict:
19
+ """Execute list command."""
20
+ try:
21
+ # This is a simplified list - in a real implementation,
22
+ # this would query the command registry
23
+ commands = [
24
+ {
25
+ "name": "echo",
26
+ "description": "Echo command that returns the input message",
27
+ "version": "1.0.0"
28
+ },
29
+ {
30
+ "name": "list",
31
+ "description": "List available commands",
32
+ "version": "1.0.0"
33
+ },
34
+ {
35
+ "name": "health",
36
+ "description": "Health check command",
37
+ "version": "1.0.0"
38
+ },
39
+ {
40
+ "name": "help",
41
+ "description": "Help command",
42
+ "version": "1.0.0"
43
+ }
44
+ ]
45
+
46
+ return {
47
+ "commands": commands,
48
+ "count": len(commands),
49
+ "timestamp": self._get_timestamp()
50
+ }
51
+ except Exception as e:
52
+ raise MicroserviceError(f"List command failed: {str(e)}")
53
+
54
+ def _get_timestamp(self):
55
+ """Get current timestamp."""
56
+ import time
57
+ return time.time()
@@ -0,0 +1,5 @@
1
+ """Full Application Hooks.
2
+
3
+ Application and command hooks for the full application example.
4
+ """
5
+
@@ -0,0 +1,29 @@
1
+ """
2
+ Application Hooks
3
+ This module demonstrates application-level hooks in the full application example.
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class ApplicationHooks:
15
+ """Application-level hooks."""
16
+
17
+ @staticmethod
18
+
19
+ @staticmethod
20
+
21
+ @staticmethod
22
+
23
+ @staticmethod
24
+
25
+ @staticmethod
26
+
27
+ @staticmethod
28
+
29
+ @staticmethod
@@ -0,0 +1,27 @@
1
+ """
2
+ Built-in Command Hooks
3
+ This module demonstrates hooks for built-in commands in the full application example.
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class BuiltinCommandHooks:
15
+ """Hooks for built-in commands."""
16
+
17
+ @staticmethod
18
+
19
+ @staticmethod
20
+
21
+ @staticmethod
22
+
23
+ @staticmethod
24
+
25
+ @staticmethod
26
+
27
+ @staticmethod
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Full Application Example
4
+ This is a complete application that demonstrates all features of MCP Proxy Adapter framework:
5
+ - Built-in commands
6
+ - Custom commands
7
+ - Dynamically loaded commands
8
+ - Built-in command hooks
9
+ - Application hooks
10
+ Author: Vasiliy Zdanovskiy
11
+ email: vasilyvz@gmail.com
12
+ """
13
+ import argparse
14
+ import asyncio
15
+ import json
16
+ from pathlib import Path
17
+
18
+ from mcp_proxy_adapter.api.app import create_app
19
+ from mcp_proxy_adapter.core.server_engine import ServerEngineFactory
20
+ from mcp_proxy_adapter.core.server_adapter import ServerConfigAdapter
21
+ from mcp_proxy_adapter.client.proxy import ProxyClient
22
+ from mcp_proxy_adapter.commands.command_registry import registry
23
+
24
+
25
+ def register_all_commands():
26
+ """Register all available commands (built-in, load, queue)."""
27
+ from mcp_proxy_adapter.commands.load_command import LoadCommand
28
+
29
+ # Register load command
30
+ registry._commands["load"] = LoadCommand
31
+ registry._command_types["load"] = "builtin"
32
+
33
+ # Register queue commands (will fail gracefully if queuemgr not available)
34
+ try:
35
+ from mcp_proxy_adapter.commands.queue_commands import (
36
+ QueueAddJobCommand,
37
+ QueueStartJobCommand,
38
+ QueueStopJobCommand,
39
+ QueueDeleteJobCommand,
40
+ QueueGetJobStatusCommand,
41
+ QueueListJobsCommand,
42
+ QueueHealthCommand,
43
+ )
44
+ registry._commands["queue_add_job"] = QueueAddJobCommand
45
+ registry._command_types["queue_add_job"] = "builtin"
46
+ registry._commands["queue_start_job"] = QueueStartJobCommand
47
+ registry._command_types["queue_start_job"] = "builtin"
48
+ registry._commands["queue_stop_job"] = QueueStopJobCommand
49
+ registry._command_types["queue_stop_job"] = "builtin"
50
+ registry._commands["queue_delete_job"] = QueueDeleteJobCommand
51
+ registry._command_types["queue_delete_job"] = "builtin"
52
+ registry._commands["queue_get_job_status"] = QueueGetJobStatusCommand
53
+ registry._command_types["queue_get_job_status"] = "builtin"
54
+ registry._commands["queue_list_jobs"] = QueueListJobsCommand
55
+ registry._command_types["queue_list_jobs"] = "builtin"
56
+ registry._commands["queue_health"] = QueueHealthCommand
57
+ registry._command_types["queue_health"] = "builtin"
58
+ print("✅ Queue commands registered")
59
+ except Exception as e:
60
+ print(f"⚠️ Queue commands not available: {e}")
61
+
62
+
63
+ def main():
64
+ """Minimal runnable entrypoint for full application example."""
65
+ parser = argparse.ArgumentParser(description="MCP Proxy Adapter Full Application")
66
+ parser.add_argument("--config", required=True, help="Path to configuration file")
67
+ parser.add_argument("--port", type=int, help="Port to run server on (override)")
68
+ parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
69
+ args = parser.parse_args()
70
+
71
+ cfg_path = Path(args.config)
72
+ if not cfg_path.exists():
73
+ print(f"❌ Configuration file not found: {cfg_path}")
74
+ raise SystemExit(1)
75
+
76
+ try:
77
+ with cfg_path.open("r", encoding="utf-8") as f:
78
+ app_config = json.load(f)
79
+ except Exception as exc: # noqa: BLE001
80
+ print(f"❌ Failed to load configuration: {exc}")
81
+ raise SystemExit(1)
82
+
83
+ if args.port:
84
+ app_config.setdefault("server", {}).update({"port": args.port})
85
+ print(f"🔧 Overriding port to {args.port}")
86
+ if args.host:
87
+ app_config.setdefault("server", {}).update({"host": args.host})
88
+ print(f"🔧 Overriding host to {args.host}")
89
+
90
+ # Strict protocol checks: forbid any form of mTLS over HTTP
91
+ proto = str(app_config.get("server", {}).get("protocol", "http")).lower()
92
+ ssl_cfg = app_config.get("ssl", {}) or {}
93
+ transport = app_config.get("transport", {}) or {}
94
+ require_client_cert = bool(
95
+ ssl_cfg.get("require_client_cert") or transport.get("verify_client")
96
+ )
97
+
98
+ # --- SimpleConfig compatibility bridge: synthesize ssl section when absent ---
99
+ if not app_config.get("ssl") and isinstance(app_config.get("server"), dict):
100
+ srv = app_config["server"]
101
+ cert_file = srv.get("cert_file")
102
+ key_file = srv.get("key_file")
103
+ ca_file = srv.get("ca_cert_file")
104
+ if cert_file and key_file:
105
+ app_config["ssl"] = {
106
+ "enabled": True,
107
+ "cert_file": cert_file,
108
+ "key_file": key_file,
109
+ }
110
+ if ca_file:
111
+ app_config["ssl"]["ca_cert"] = ca_file
112
+ # For mtls protocol, enforce client verification
113
+ if proto == "mtls":
114
+ app_config.setdefault("transport", {}).update({"verify_client": True})
115
+ # Refresh local vars after synthesis
116
+ ssl_cfg = app_config.get("ssl", {}) or {}
117
+ transport = app_config.get("transport", {}) or {}
118
+ require_client_cert = bool(
119
+ ssl_cfg.get("require_client_cert") or transport.get("verify_client")
120
+ )
121
+ # ---------------------------------------------------------------------------
122
+
123
+ if proto == "http":
124
+ if require_client_cert:
125
+ raise SystemExit(
126
+ "CRITICAL CONFIG ERROR: mTLS (client certificate verification) cannot be used with HTTP. "
127
+ "Switch protocol to 'mtls' (or 'https' without client verification), and configure SSL certificates."
128
+ )
129
+
130
+ if proto == "mtls":
131
+ if not ssl_cfg.get("enabled"):
132
+ raise SystemExit(
133
+ "CRITICAL CONFIG ERROR: Protocol 'mtls' requires SSL to be enabled."
134
+ )
135
+ if not require_client_cert:
136
+ raise SystemExit(
137
+ "CRITICAL CONFIG ERROR: Protocol 'mtls' requires client certificate verification. "
138
+ "Set ssl.require_client_cert=true or transport.verify_client=true."
139
+ )
140
+ cert = ssl_cfg.get("certfile") or ssl_cfg.get("cert_file")
141
+ key = ssl_cfg.get("keyfile") or ssl_cfg.get("key_file")
142
+ ca = ssl_cfg.get("cafile") or ssl_cfg.get("ca_cert") or ssl_cfg.get("ca_cert_file")
143
+ if not (cert and key and ca):
144
+ raise SystemExit(
145
+ "CRITICAL CONFIG ERROR: 'mtls' requires ssl.certfile/keyfile (or cert_file/key_file) and CA certificate."
146
+ )
147
+
148
+ app = create_app(title="Full Application Example", description="Complete MCP Proxy Adapter with all features", version="1.0.0", app_config=app_config, config_path=str(cfg_path))
149
+
150
+ port = int(app_config.get("server", {}).get("port", 8080))
151
+ host = app_config.get("server", {}).get("host", args.host)
152
+
153
+ print("🚀 Starting Full Application Example")
154
+ print(f"📋 Configuration: {cfg_path}")
155
+ print("============================================================")
156
+
157
+ # Register all commands
158
+ register_all_commands()
159
+ print(f"📋 Registered commands: {', '.join(sorted(registry.get_all_commands().keys()))}")
160
+
161
+ # Prepare server configuration for ServerEngine
162
+ server_config = {
163
+ "host": host,
164
+ "port": port,
165
+ "log_level": "info",
166
+ "reload": False,
167
+ }
168
+
169
+ # Add SSL configuration if enabled
170
+ ssl_cfg = app_config.get("ssl", {})
171
+ if ssl_cfg.get("enabled"):
172
+ cert = ssl_cfg.get("certfile") or ssl_cfg.get("cert_file")
173
+ key = ssl_cfg.get("keyfile") or ssl_cfg.get("key_file")
174
+ ca = ssl_cfg.get("cafile") or ssl_cfg.get("ca_cert") or ssl_cfg.get("ca_cert_file")
175
+ if cert and key:
176
+ server_config["certfile"] = cert
177
+ server_config["keyfile"] = key
178
+ if ca:
179
+ server_config["ca_certs"] = ca
180
+ if ssl_cfg.get("verify_client") or app_config.get("transport", {}).get("verify_client"):
181
+ server_config["verify_mode"] = 2 # ssl.CERT_REQUIRED
182
+ if "chk_hostname" in ssl_cfg:
183
+ server_config["check_hostname"] = ssl_cfg["chk_hostname"]
184
+
185
+ # Optional proxy registration
186
+ pr = (app_config.get("proxy_registration") or {}) if isinstance(app_config, dict) else {}
187
+ name = pr.get("server_id") or pr.get("server_name") or "mcp-adapter"
188
+ scheme = "https" if str(app_config.get("server", {}).get("protocol", "http")) in ("https", "mtls") else "http"
189
+ advertised_host = app_config.get("server", {}).get("advertised_host") or "mcp-adapter"
190
+ advertised_url = f"{scheme}://{advertised_host}:{port}"
191
+
192
+ async def _run():
193
+ """Run server with proxy registration and heartbeat."""
194
+ heartbeat_task = None
195
+ try:
196
+ if pr.get("enabled") and pr.get("proxy_url"):
197
+ pc = ProxyClient(pr["proxy_url"])
198
+ try:
199
+ pc.register(name=name, url=advertised_url, capabilities=["jsonrpc"], metadata={})
200
+ print(f"✅ Registered on proxy as {name} -> {advertised_url}")
201
+ except Exception as exc: # noqa: BLE001
202
+ print(f"⚠️ Proxy registration failed: {exc}")
203
+
204
+ async def _hb():
205
+ interval = int((pr.get("heartbeat") or {}).get("interval", 15))
206
+ while True:
207
+ try:
208
+ pc.heartbeat(name=name, url=advertised_url)
209
+ except Exception:
210
+ pass
211
+ await asyncio.sleep(max(2, interval))
212
+
213
+ heartbeat_task = asyncio.create_task(_hb())
214
+
215
+ # Use ServerEngine with hypercorn (via ServerEngineFactory)
216
+ engine = ServerEngineFactory.get_engine("hypercorn")
217
+ if not engine:
218
+ raise RuntimeError("Hypercorn engine not available")
219
+
220
+ # Convert SSL config if needed
221
+ if "ssl" in app_config:
222
+ ssl_converted = ServerConfigAdapter.convert_ssl_config_for_engine(
223
+ app_config["ssl"], "hypercorn"
224
+ )
225
+ server_config.update(ssl_converted)
226
+
227
+ # Run server using hypercorn engine
228
+ # Use create_task instead of run_server to avoid nested event loop
229
+ from hypercorn.asyncio import serve
230
+ from hypercorn.config import Config as HypercornConfig
231
+
232
+ hypercorn_config = HypercornConfig()
233
+ hypercorn_config.bind = [f"{host}:{port}"]
234
+ hypercorn_config.loglevel = "info"
235
+
236
+ # Add SSL configuration if enabled
237
+ if ssl_cfg.get("enabled"):
238
+ cert = ssl_cfg.get("certfile") or ssl_cfg.get("cert_file")
239
+ key = ssl_cfg.get("keyfile") or ssl_cfg.get("key_file")
240
+ ca = ssl_cfg.get("cafile") or ssl_cfg.get("ca_cert") or ssl_cfg.get("ca_cert_file")
241
+ if cert and key:
242
+ hypercorn_config.certfile = cert
243
+ hypercorn_config.keyfile = key
244
+ if ca:
245
+ hypercorn_config.ca_certs = ca
246
+ if ssl_cfg.get("verify_client") or app_config.get("transport", {}).get("verify_client"):
247
+ hypercorn_config.verify_mode = 2 # ssl.CERT_REQUIRED
248
+
249
+ await serve(app, hypercorn_config)
250
+ finally:
251
+ if heartbeat_task:
252
+ heartbeat_task.cancel()
253
+ if pr.get("enabled") and pr.get("proxy_url"):
254
+ try:
255
+ ProxyClient(pr["proxy_url"]).unregister(name)
256
+ print(f"🛑 Unregistered from proxy: {name}")
257
+ except Exception:
258
+ pass
259
+
260
+ asyncio.run(_run())
261
+
262
+
263
+ if __name__ == "__main__":
264
+ main()
@@ -0,0 +1,81 @@
1
+ """
2
+ Proxy Registration Endpoints
3
+ This module provides proxy registration endpoints for testing.
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+
8
+ from fastapi import APIRouter, HTTPException
9
+ from pydantic import BaseModel
10
+ from typing import Dict, List, Optional
11
+ import time
12
+ import uuid
13
+
14
+ # In-memory registry for testing
15
+ _registry: Dict[str, Dict] = {}
16
+ router = APIRouter(prefix="/proxy", tags=["proxy"])
17
+
18
+
19
+ class ServerRegistration(BaseModel):
20
+ """Server registration request model."""
21
+
22
+ server_id: str
23
+ server_url: str
24
+ server_name: str
25
+ description: Optional[str] = None
26
+ version: Optional[str] = "1.0.0"
27
+ capabilities: Optional[List[str]] = None
28
+ endpoints: Optional[Dict[str, str]] = None
29
+ auth_method: Optional[str] = "none"
30
+ security_enabled: Optional[bool] = False
31
+
32
+
33
+ class ServerUnregistration(BaseModel):
34
+ """Server unregistration request model."""
35
+
36
+ server_key: str # Use server_key directly
37
+
38
+
39
+ class HeartbeatData(BaseModel):
40
+ """Heartbeat data model."""
41
+
42
+ server_id: str
43
+ server_key: str
44
+ timestamp: Optional[int] = None
45
+ status: Optional[str] = "healthy"
46
+
47
+
48
+ class RegistrationResponse(BaseModel):
49
+ """Registration response model."""
50
+
51
+ success: bool
52
+ server_key: str
53
+ message: str
54
+ copy_number: int
55
+
56
+
57
+ class DiscoveryResponse(BaseModel):
58
+ """Discovery response model."""
59
+
60
+ success: bool
61
+ servers: List[Dict]
62
+ total: int
63
+ active: int
64
+
65
+
66
+ @router.post("/register", response_model=RegistrationResponse)
67
+
68
+
69
+ @router.post("/unregister")
70
+
71
+
72
+ @router.post("/heartbeat")
73
+
74
+
75
+ @router.get("/discover", response_model=DiscoveryResponse)
76
+
77
+
78
+ @router.get("/status")
79
+
80
+
81
+ @router.delete("/clear")