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,484 @@
1
+ """
2
+ Key Management Command
3
+
4
+ This module provides commands for key management including generation,
5
+ validation, rotation, backup, and restoration.
6
+
7
+ Author: MCP Proxy Adapter Team
8
+ Version: 1.0.0
9
+ """
10
+
11
+ import logging
12
+ import os
13
+ import shutil
14
+ from pathlib import Path
15
+ from datetime import datetime
16
+
17
+ from .base import Command
18
+ from .result import CommandResult, SuccessResult, ErrorResult
19
+ from ..core.certificate_utils import CertificateUtils
20
+
21
+ from mcp_proxy_adapter.core.logging import get_global_logger
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class KeyResult:
26
+ """
27
+ Result class for key operations.
28
+
29
+ Contains key information and operation status.
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ key_path: str,
35
+ key_type: str,
36
+ key_size: int,
37
+ created_date: Optional[str] = None,
38
+ expiry_date: Optional[str] = None,
39
+ status: str = "valid",
40
+ error: Optional[str] = None,
41
+ ):
42
+ """
43
+ Initialize key result.
44
+
45
+ Args:
46
+ key_path: Path to key file
47
+ key_type: Type of key (RSA, ECDSA, etc.)
48
+ key_size: Key size in bits
49
+ created_date: Key creation date
50
+ expiry_date: Key expiry date
51
+ status: Key status (valid, expired, error)
52
+ error: Error message if any
53
+ """
54
+ self.key_path = key_path
55
+ self.key_type = key_type
56
+ self.key_size = key_size
57
+ self.created_date = created_date
58
+ self.expiry_date = expiry_date
59
+ self.status = status
60
+ self.error = error
61
+
62
+ def to_dict(self) -> Dict[str, Any]:
63
+ """
64
+ Convert to dictionary format.
65
+
66
+ Returns:
67
+ Dictionary representation
68
+ """
69
+ return {
70
+ "key_path": self.key_path,
71
+ "key_type": self.key_type,
72
+ "key_size": self.key_size,
73
+ "created_date": self.created_date,
74
+ "expiry_date": self.expiry_date,
75
+ "status": self.status,
76
+ "error": self.error,
77
+ }
78
+
79
+ @classmethod
80
+
81
+
82
+ class KeyManagementCommand(Command):
83
+ """
84
+ Command for key management.
85
+
86
+ Provides methods for generating, validating, rotating, backing up, and restoring keys.
87
+ """
88
+
89
+ # Command metadata
90
+ name = "key_management"
91
+ version = "1.0.0"
92
+ descr = "Private key generation, validation, and management"
93
+ category = "security"
94
+ author = "MCP Proxy Adapter Team"
95
+ email = "team@mcp-proxy-adapter.com"
96
+ source_url = "https://github.com/mcp-proxy-adapter"
97
+ result_class = KeyResult
98
+
99
+ def __init__(self):
100
+ """Initialize key management command."""
101
+ super().__init__()
102
+ self.certificate_utils = CertificateUtils()
103
+
104
+ async def execute(self, **kwargs) -> CommandResult:
105
+ """
106
+ Execute key management command.
107
+
108
+ Args:
109
+ **kwargs: Command parameters including:
110
+ - action: Action to perform (key_generate, key_validate, key_rotate, key_backup, key_restore)
111
+ - key_type: Type of key to generate (RSA, ECDSA)
112
+ - key_size: Key size in bits for generation
113
+ - output_path: Output path for key generation
114
+ - password: Password for key encryption
115
+ - key_path: Key file path for validation, rotation, backup
116
+ - old_key_path: Old key path for rotation
117
+ - new_key_path: New key path for rotation
118
+ - cert_path: Certificate path for rotation
119
+ - backup_old: Whether to backup old key during rotation
120
+ - backup_path: Backup path for key backup/restore
121
+ - encrypt_backup: Whether to encrypt backup
122
+
123
+ Returns:
124
+ CommandResult with key operation status
125
+ """
126
+ action = kwargs.get("action", "key_validate")
127
+
128
+ if action == "key_generate":
129
+ key_type = kwargs.get("key_type")
130
+ key_size = kwargs.get("key_size")
131
+ output_path = kwargs.get("output_path")
132
+ password = kwargs.get("password")
133
+ return await self.key_generate(key_type, key_size, output_path, password)
134
+ elif action == "key_validate":
135
+ key_path = kwargs.get("key_path")
136
+ password = kwargs.get("password")
137
+ return await self.key_validate(key_path, password)
138
+ elif action == "key_rotate":
139
+ old_key_path = kwargs.get("old_key_path")
140
+ new_key_path = kwargs.get("new_key_path")
141
+ cert_path = kwargs.get("cert_path")
142
+ backup_old = kwargs.get("backup_old", True)
143
+ return await self.key_rotate(
144
+ old_key_path, new_key_path, cert_path, backup_old
145
+ )
146
+ elif action == "key_backup":
147
+ key_path = kwargs.get("key_path")
148
+ backup_path = kwargs.get("backup_path")
149
+ encrypt_backup = kwargs.get("encrypt_backup", True)
150
+ password = kwargs.get("password")
151
+ return await self.key_backup(
152
+ key_path, backup_path, encrypt_backup, password
153
+ )
154
+ elif action == "key_restore":
155
+ backup_path = kwargs.get("backup_path")
156
+ key_path = kwargs.get("key_path")
157
+ password = kwargs.get("password")
158
+ return await self.key_restore(backup_path, key_path, password)
159
+ else:
160
+ return ErrorResult(
161
+ message=f"Unknown action: {action}. Supported actions: key_generate, key_validate, key_rotate, key_backup, key_restore"
162
+ )
163
+
164
+ async def key_generate(
165
+ self,
166
+ key_type: str,
167
+ key_size: int,
168
+ output_path: str,
169
+ password: Optional[str] = None,
170
+ ) -> CommandResult:
171
+ """
172
+ Generate a new private key.
173
+
174
+ Args:
175
+ key_type: Type of key to generate (RSA, ECDSA)
176
+ key_size: Key size in bits
177
+ output_path: Path to save the generated key
178
+ password: Optional password to encrypt the key
179
+
180
+ Returns:
181
+ CommandResult with key generation status
182
+ """
183
+ try:
184
+ get_global_logger().info(f"Generating {key_type} key with size {key_size} bits")
185
+
186
+ # Validate parameters
187
+ if key_type not in ["RSA", "ECDSA"]:
188
+ return ErrorResult(message="Key type must be RSA or ECDSA")
189
+
190
+ if key_type == "ECDSA":
191
+ if key_size not in [256, 384, 521]:
192
+ return ErrorResult(
193
+ message="ECDSA key size must be 256, 384, or 521 bits"
194
+ )
195
+ elif key_size < 1024:
196
+ return ErrorResult(message="Key size must be at least 1024 bits")
197
+
198
+ # Create output directory if it doesn't exist
199
+ output_dir = os.path.dirname(output_path)
200
+ if output_dir:
201
+ Path(output_dir).mkdir(parents=True, exist_ok=True)
202
+
203
+ # Generate key
204
+ result = self.certificate_utils.generate_private_key(
205
+ key_type, key_size, output_path
206
+ )
207
+
208
+ if not result["success"]:
209
+ return ErrorResult(message=f"Key generation failed: {result['error']}")
210
+
211
+ key_result = KeyResult(
212
+ key_path=output_path,
213
+ key_type=key_type,
214
+ key_size=key_size,
215
+ created_date=datetime.now().isoformat(),
216
+ status="valid",
217
+ )
218
+
219
+ get_global_logger().info(f"Key generated successfully: {output_path}")
220
+ return SuccessResult(data={"key": key_result.to_dict(), "details": result})
221
+
222
+ except Exception as e:
223
+ get_global_logger().error(f"Key generation failed: {e}")
224
+ return ErrorResult(message=f"Key generation failed: {str(e)}")
225
+
226
+ async def key_validate(
227
+ self, key_path: str, password: Optional[str] = None
228
+ ) -> CommandResult:
229
+ """
230
+ Validate a private key.
231
+
232
+ Args:
233
+ key_path: Path to key file to validate
234
+ password: Optional password if key is encrypted
235
+
236
+ Returns:
237
+ CommandResult with key validation status
238
+ """
239
+ try:
240
+ get_global_logger().info(f"Validating key: {key_path}")
241
+
242
+ # Validate parameters
243
+ if not key_path or not os.path.exists(key_path):
244
+ return ErrorResult(message=f"Key file not found: {key_path}")
245
+
246
+ # Validate key
247
+ result = self.certificate_utils.validate_private_key(key_path)
248
+
249
+ if not result["success"]:
250
+ return ErrorResult(message=f"Key validation failed: {result['error']}")
251
+
252
+ key_result = KeyResult(
253
+ key_path=key_path,
254
+ key_type=result.get("key_type", "unknown"),
255
+ key_size=result.get("key_size", 0),
256
+ created_date=result.get("created_date"),
257
+ status="valid",
258
+ )
259
+
260
+ get_global_logger().info(f"Key validation completed: {key_path}")
261
+ return SuccessResult(data={"key": key_result.to_dict()})
262
+
263
+ except Exception as e:
264
+ get_global_logger().error(f"Key validation failed: {e}")
265
+ return ErrorResult(message=f"Key validation failed: {str(e)}")
266
+
267
+ async def key_rotate(
268
+ self,
269
+ old_key_path: str,
270
+ new_key_path: str,
271
+ cert_path: Optional[str] = None,
272
+ backup_old: bool = True,
273
+ ) -> CommandResult:
274
+ """
275
+ Rotate a private key.
276
+
277
+ Args:
278
+ old_key_path: Path to old key file
279
+ new_key_path: Path to new key file
280
+ cert_path: Optional certificate path to update with new key
281
+ backup_old: Whether to backup the old key
282
+
283
+ Returns:
284
+ CommandResult with key rotation status
285
+ """
286
+ try:
287
+ get_global_logger().info(f"Rotating key from {old_key_path} to {new_key_path}")
288
+
289
+ # Validate parameters
290
+ if not old_key_path or not os.path.exists(old_key_path):
291
+ return ErrorResult(message=f"Old key file not found: {old_key_path}")
292
+
293
+ if not new_key_path or not os.path.exists(new_key_path):
294
+ return ErrorResult(message=f"New key file not found: {new_key_path}")
295
+
296
+ # Validate both keys
297
+ old_key_validation = await self.key_validate(old_key_path)
298
+ new_key_validation = await self.key_validate(new_key_path)
299
+
300
+ if not old_key_validation.to_dict()["success"]:
301
+ return ErrorResult(
302
+ message=f"Old key validation failed: {old_key_validation.to_dict()['error']['message']}"
303
+ )
304
+
305
+ if not new_key_validation.to_dict()["success"]:
306
+ return ErrorResult(
307
+ message=f"New key validation failed: {new_key_validation.to_dict()['error']['message']}"
308
+ )
309
+
310
+ # Backup old key if requested
311
+ backup_path = None
312
+ if backup_old:
313
+ backup_path = (
314
+ f"{old_key_path}.backup.{datetime.now().strftime('%Y%m%d_%H%M%S')}"
315
+ )
316
+ shutil.copy2(old_key_path, backup_path)
317
+ get_global_logger().info(f"Old key backed up to: {backup_path}")
318
+
319
+ # Update certificate if provided
320
+ cert_updated = False
321
+ if cert_path and os.path.exists(cert_path):
322
+ try:
323
+ # This would require implementing certificate re-signing
324
+ # For now, we'll just note that it needs to be done
325
+ cert_updated = True
326
+ get_global_logger().info(
327
+ f"Certificate {cert_path} needs to be re-signed with new key"
328
+ )
329
+ except Exception as e:
330
+ get_global_logger().warning(f"Could not update certificate {cert_path}: {e}")
331
+
332
+ # Replace old key with new key
333
+ shutil.copy2(new_key_path, old_key_path)
334
+
335
+ get_global_logger().info(f"Key rotation completed successfully")
336
+ return SuccessResult(
337
+ data={
338
+ "old_key_path": old_key_path,
339
+ "new_key_path": new_key_path,
340
+ "backup_path": backup_path,
341
+ "cert_updated": cert_updated,
342
+ "message": "Key rotation completed successfully",
343
+ }
344
+ )
345
+
346
+ except Exception as e:
347
+ get_global_logger().error(f"Key rotation failed: {e}")
348
+ return ErrorResult(message=f"Key rotation failed: {str(e)}")
349
+
350
+ async def key_backup(
351
+ self,
352
+ key_path: str,
353
+ backup_path: str,
354
+ encrypt_backup: bool = True,
355
+ password: Optional[str] = None,
356
+ ) -> CommandResult:
357
+ """
358
+ Backup a private key.
359
+
360
+ Args:
361
+ key_path: Path to key file to backup
362
+ backup_path: Path to save the backup
363
+ encrypt_backup: Whether to encrypt the backup
364
+ password: Password for backup encryption
365
+
366
+ Returns:
367
+ CommandResult with backup status
368
+ """
369
+ try:
370
+ get_global_logger().info(f"Backing up key: {key_path}")
371
+
372
+ # Validate parameters
373
+ if not key_path or not os.path.exists(key_path):
374
+ return ErrorResult(message=f"Key file not found: {key_path}")
375
+
376
+ # Validate key before backup
377
+ key_validation = await self.key_validate(key_path)
378
+ if not key_validation.to_dict()["success"]:
379
+ return ErrorResult(
380
+ message=f"Key validation failed before backup: {key_validation.to_dict()['error']['message']}"
381
+ )
382
+
383
+ # Create backup directory if it doesn't exist
384
+ backup_dir = os.path.dirname(backup_path)
385
+ if backup_dir:
386
+ Path(backup_dir).mkdir(parents=True, exist_ok=True)
387
+
388
+ # Create backup
389
+ if encrypt_backup and password:
390
+ # Encrypted backup
391
+ result = self.certificate_utils.create_encrypted_backup(
392
+ key_path, backup_path, password
393
+ )
394
+ if not result["success"]:
395
+ return ErrorResult(
396
+ message=f"Encrypted backup failed: {result['error']}"
397
+ )
398
+ else:
399
+ # Simple file copy
400
+ shutil.copy2(key_path, backup_path)
401
+
402
+ # Verify backup
403
+ if not os.path.exists(backup_path):
404
+ return ErrorResult(message="Backup file was not created")
405
+
406
+ get_global_logger().info(f"Key backup completed successfully: {backup_path}")
407
+ return SuccessResult(
408
+ data={
409
+ "key_path": key_path,
410
+ "backup_path": backup_path,
411
+ "encrypted": encrypt_backup,
412
+ "backup_size": os.path.getsize(backup_path),
413
+ "backup_date": datetime.now().isoformat(),
414
+ }
415
+ )
416
+
417
+ except Exception as e:
418
+ get_global_logger().error(f"Key backup failed: {e}")
419
+ return ErrorResult(message=f"Key backup failed: {str(e)}")
420
+
421
+ async def key_restore(
422
+ self, backup_path: str, key_path: str, password: Optional[str] = None
423
+ ) -> CommandResult:
424
+ """
425
+ Restore a private key from backup.
426
+
427
+ Args:
428
+ backup_path: Path to backup file
429
+ key_path: Path to restore the key to
430
+ password: Password if backup is encrypted
431
+
432
+ Returns:
433
+ CommandResult with restore status
434
+ """
435
+ try:
436
+ get_global_logger().info(f"Restoring key from backup: {backup_path}")
437
+
438
+ # Validate parameters
439
+ if not backup_path or not os.path.exists(backup_path):
440
+ return ErrorResult(message=f"Backup file not found: {backup_path}")
441
+
442
+ # Create target directory if it doesn't exist
443
+ key_dir = os.path.dirname(key_path)
444
+ if key_dir:
445
+ Path(key_dir).mkdir(parents=True, exist_ok=True)
446
+
447
+ # Restore key
448
+ if password:
449
+ # Try encrypted restore first
450
+ result = self.certificate_utils.restore_encrypted_backup(
451
+ backup_path, key_path, password
452
+ )
453
+ if not result["success"]:
454
+ return ErrorResult(
455
+ message=f"Encrypted restore failed: {result['error']}"
456
+ )
457
+ else:
458
+ # Simple file copy
459
+ shutil.copy2(backup_path, key_path)
460
+
461
+ # Validate restored key
462
+ key_validation = await self.key_validate(key_path)
463
+ if not key_validation.to_dict()["success"]:
464
+ return ErrorResult(
465
+ message=f"Restored key validation failed: {key_validation.to_dict()['error']['message']}"
466
+ )
467
+
468
+ get_global_logger().info(f"Key restore completed successfully: {key_path}")
469
+ return SuccessResult(
470
+ data={
471
+ "backup_path": backup_path,
472
+ "key_path": key_path,
473
+ "restore_date": datetime.now().isoformat(),
474
+ "key_info": (
475
+ key_validation.to_dict().get("data", {}).get("key")
476
+ if key_validation.to_dict().get("success")
477
+ else None
478
+ ),
479
+ }
480
+ )
481
+
482
+ except Exception as e:
483
+ get_global_logger().error(f"Key restore failed: {e}")
484
+ return ErrorResult(message=f"Key restore failed: {str(e)}")
@@ -0,0 +1,123 @@
1
+ """
2
+ Module with load 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
+ from mcp_proxy_adapter.commands.result import SuccessResult
10
+
11
+
12
+ class LoadResult(SuccessResult):
13
+ """
14
+ Result of the load command execution.
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ success: bool,
20
+ commands_loaded: int,
21
+ loaded_commands: list,
22
+ source: str,
23
+ error: Optional[str] = None,
24
+ ):
25
+ """
26
+ Initialize load command result.
27
+
28
+ Args:
29
+ success: Whether loading was successful
30
+ commands_loaded: Number of commands loaded
31
+ loaded_commands: List of loaded command names
32
+ source: Source path or URL
33
+ error: Error message if loading failed
34
+ """
35
+ data = {
36
+ "success": success,
37
+ "commands_loaded": commands_loaded,
38
+ "loaded_commands": loaded_commands,
39
+ "source": source,
40
+ }
41
+ if error:
42
+ data["error"] = error
43
+
44
+ message = f"Loaded {commands_loaded} commands from {source}"
45
+ if error:
46
+ message = f"Failed to load commands from {source}: {error}"
47
+
48
+ super().__init__(data=data, message=message)
49
+
50
+ @classmethod
51
+ def get_schema(cls) -> Dict[str, Any]:
52
+ return {
53
+ "type": "object",
54
+ "properties": {
55
+ "success": {"type": "boolean"},
56
+ "commands_loaded": {"type": "integer"},
57
+ "loaded_commands": {"type": "array", "items": {"type": "string"}},
58
+ "source": {"type": "string"},
59
+ "error": {"type": "string"},
60
+ },
61
+ }
62
+
63
+
64
+ class LoadCommand(Command):
65
+ """
66
+ Command that loads commands from local path or URL.
67
+
68
+ This command allows dynamic loading of command modules from either local file system
69
+ or remote HTTP/HTTPS URLs. The command automatically detects whether the source
70
+ is a local path or URL and handles the loading accordingly.
71
+
72
+ For local paths, the command loads Python modules ending with '_command.py'.
73
+ For URLs, the command downloads the Python code and loads it as a temporary module.
74
+
75
+ The loaded commands are registered in the command registry and become immediately
76
+ available for execution. Only commands that inherit from the base Command class
77
+ and are properly structured will be loaded and registered.
78
+
79
+ Security considerations:
80
+ - Local paths are validated for existence and proper naming
81
+ - URLs are downloaded with timeout protection
82
+ - Temporary files are automatically cleaned up after loading
83
+ - Only files ending with '_command.py' are accepted
84
+
85
+ Examples:
86
+ - Load from local file: "./my_command.py"
87
+ - Load from URL: "https://example.com/remote_command.py"
88
+ """
89
+
90
+ name = "load"
91
+ result_class = LoadResult
92
+
93
+ async def execute(self, source: str, **kwargs) -> LoadResult:
94
+ """
95
+ Execute load command.
96
+
97
+ Args:
98
+ source: Source path or URL to load command from
99
+ **kwargs: Additional parameters
100
+
101
+ Returns:
102
+ LoadResult: Load command result
103
+ """
104
+ # Load command from source
105
+ result = registry.load_command_from_source(source)
106
+
107
+ return LoadResult(
108
+ success=result.get("success", False),
109
+ commands_loaded=result.get("commands_loaded", 0),
110
+ loaded_commands=result.get("loaded_commands", []),
111
+ source=result.get("source", source),
112
+ error=result.get("error"),
113
+ )
114
+
115
+ @classmethod
116
+ def get_schema(cls) -> Dict[str, Any]:
117
+ return {
118
+ "type": "object",
119
+ "properties": {
120
+ "source": {"type": "string", "description": "Path or URL to command file"}
121
+ },
122
+ "required": ["source"],
123
+ }