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,389 @@
1
+ """
2
+ Base command classes for MCP Microservice.
3
+ """
4
+
5
+ import inspect
6
+ from abc import ABC, abstractmethod
7
+ from typing import TypeVar, Type, ClassVar, Dict, Any, List
8
+
9
+ from docstring_parser import parse
10
+
11
+ from mcp_proxy_adapter.core.errors import (
12
+ CommandError,
13
+ InternalError,
14
+ InvalidParamsError,
15
+ NotFoundError,
16
+ ValidationError,
17
+ )
18
+ from mcp_proxy_adapter.core.logging import get_global_logger
19
+
20
+
21
+ class CommandResult:
22
+ """Base class for command results."""
23
+
24
+ def __init__(self, success: bool = True, data: dict = None, error: str = None):
25
+ self.success = success
26
+ self.data = data or {}
27
+ self.error = error
28
+
29
+ def to_dict(self) -> dict:
30
+ """Convert to dictionary."""
31
+ result = {"success": self.success}
32
+ if self.data:
33
+ result["data"] = self.data
34
+ if self.error:
35
+ result["error"] = self.error
36
+ return result
37
+
38
+
39
+ T = TypeVar("T", bound=CommandResult)
40
+
41
+
42
+ class Command(ABC):
43
+ """
44
+ Base abstract class for all commands.
45
+ """
46
+
47
+ # Command name for registration
48
+ name: ClassVar[str]
49
+ # Command version (default: 0.1)
50
+ version: ClassVar[str] = "0.1"
51
+ # Plugin filename
52
+ plugin: ClassVar[str] = ""
53
+ # Command description
54
+ descr: ClassVar[str] = ""
55
+ # Command category
56
+ category: ClassVar[str] = ""
57
+ # Command author
58
+ author: ClassVar[str] = ""
59
+ # Author email
60
+ email: ClassVar[str] = ""
61
+ # Source URL
62
+ source_url: ClassVar[str] = ""
63
+ # Result class
64
+ result_class: ClassVar[Type[CommandResult]]
65
+
66
+ @abstractmethod
67
+ async def execute(self, **kwargs) -> CommandResult:
68
+ """
69
+ Execute command with the specified parameters.
70
+
71
+ Args:
72
+ **kwargs: Command parameters including optional 'context' parameter.
73
+
74
+ Returns:
75
+ Command result.
76
+ """
77
+ pass
78
+
79
+ @classmethod
80
+ def get_schema(cls) -> Dict[str, Any]:
81
+ """
82
+ Get JSON schema for command parameters.
83
+
84
+ Returns:
85
+ JSON schema.
86
+ """
87
+ return {"type": "object", "properties": {}, "additionalProperties": False}
88
+
89
+ @classmethod
90
+ def get_result_schema(cls) -> Dict[str, Any]:
91
+ """
92
+ Get JSON schema for command result.
93
+
94
+ Returns:
95
+ JSON schema.
96
+ """
97
+ if hasattr(cls, "result_class") and cls.result_class:
98
+ return cls.result_class.get_schema()
99
+ return {}
100
+
101
+ def validate_params(self, params: Dict[str, Any]) -> Dict[str, Any]:
102
+ """
103
+ Validate command parameters.
104
+
105
+ Args:
106
+ params: Parameters to validate.
107
+
108
+ Returns:
109
+ Validated parameters.
110
+
111
+ Raises:
112
+ ValidationError: If parameters are invalid.
113
+ """
114
+ # Ensure params is a dictionary, even if None was passed
115
+ if params is None:
116
+ params = {}
117
+
118
+ # Create a copy to avoid modifying the input dictionary during iteration
119
+ validated_params = params.copy()
120
+
121
+ # Handle None values and empty strings in parameters
122
+ for key, value in list(validated_params.items()):
123
+ # Process None values or empty strings - this helps with JavaScript null/undefined conversions
124
+ if value is None or (
125
+ isinstance(value, str) and value.lower() in ["null", "none", ""]
126
+ ):
127
+ # For commands that specifically handle None values, keep the parameter
128
+ # (like help), keep the parameter but ensure it's a proper Python None
129
+ if key in [
130
+ "cmdname"
131
+ ]: # список параметров, для которых None является допустимым значением
132
+ validated_params[key] = None
133
+ else:
134
+ # For most parameters, remove None values to avoid issues
135
+ del validated_params[key]
136
+
137
+ # Get command schema to validate parameters
138
+ schema = self.get_schema()
139
+ if schema and "properties" in schema:
140
+ allowed_properties = schema["properties"].keys()
141
+
142
+ # Filter out parameters that are not in the schema
143
+ invalid_params = []
144
+ for param_name in list(validated_params.keys()):
145
+ if param_name not in allowed_properties:
146
+ invalid_params.append(param_name)
147
+ del validated_params[param_name]
148
+
149
+ # Log warning about invalid parameters
150
+ if invalid_params:
151
+ get_global_logger().warning(
152
+ f"Command {self.__class__.__name__} received invalid parameters: {invalid_params}. "
153
+ f"Allowed parameters: {list(allowed_properties)}"
154
+ )
155
+
156
+ # Validate required parameters based on command schema
157
+ if schema and "required" in schema:
158
+ required_params = schema["required"]
159
+ missing_params = []
160
+
161
+ for param in required_params:
162
+ if param not in validated_params:
163
+ missing_params.append(param)
164
+
165
+ if missing_params:
166
+ raise ValidationError(
167
+ f"Missing required parameters: {', '.join(missing_params)}",
168
+ data={"missing_parameters": missing_params},
169
+ )
170
+
171
+ return validated_params
172
+
173
+ @classmethod
174
+ async def run(cls, **kwargs) -> CommandResult:
175
+ """
176
+ Runs the command with the specified arguments.
177
+
178
+ Args:
179
+ **kwargs: Command arguments including optional 'context' parameter.
180
+
181
+ Returns:
182
+ Command result.
183
+ """
184
+ # Extract context from kwargs
185
+ context = kwargs.pop("context", {}) if "context" in kwargs else {}
186
+
187
+ try:
188
+ get_global_logger().debug(f"Running command {cls.__name__} with params: {kwargs}")
189
+
190
+ # Import registry here to avoid circular imports
191
+ from mcp_proxy_adapter.commands.command_registry import registry
192
+
193
+ # Get command name
194
+ if not hasattr(cls, "name") or not cls.name:
195
+ command_name = cls.__name__.lower()
196
+ if command_name.endswith("command"):
197
+ command_name = command_name[:-7]
198
+ else:
199
+ command_name = cls.name
200
+
201
+ # Ensure kwargs is never None
202
+ if kwargs is None:
203
+ kwargs = {}
204
+
205
+ # Get command with priority (custom commands first, then built-in)
206
+ command_class = registry.get_command(command_name)
207
+ if command_class is None:
208
+ raise NotFoundError(f"Command '{command_name}' not found")
209
+
210
+ # Create new instance and validate parameters
211
+ command = command_class()
212
+ validated_params = command.validate_params(kwargs)
213
+
214
+ # Execute command with validated parameters and context
215
+ result = await command.execute(**validated_params, context=context)
216
+
217
+ get_global_logger().debug(f"Command {cls.__name__} executed successfully")
218
+ return result
219
+ except ValidationError as e:
220
+ # Ошибка валидации параметров
221
+ get_global_logger().error(f"Validation error in command {cls.__name__}: {e}")
222
+ return ErrorResult(message=str(e), code=e.code, details=e.data)
223
+ except InvalidParamsError as e:
224
+ # Ошибка в параметрах команды
225
+ get_global_logger().error(f"Invalid parameters error in command {cls.__name__}: {e}")
226
+ return ErrorResult(message=str(e), code=e.code, details=e.data)
227
+ except NotFoundError as e:
228
+ # Ресурс не найден
229
+ get_global_logger().error(f"Resource not found error in command {cls.__name__}: {e}")
230
+ return ErrorResult(message=str(e), code=e.code, details=e.data)
231
+ except TimeoutError as e:
232
+ # Превышено время ожидания
233
+ get_global_logger().error(f"Timeout error in command {cls.__name__}: {e}")
234
+ return ErrorResult(message=str(e), code=e.code, details=e.data)
235
+ except CommandError as e:
236
+ # Ошибка выполнения команды
237
+ get_global_logger().error(f"Command error in {cls.__name__}: {e}")
238
+ return ErrorResult(message=str(e), code=e.code, details=e.data)
239
+ except Exception as e:
240
+ # Непредвиденная ошибка
241
+ get_global_logger().exception(f"Unexpected error executing command {cls.__name__}: {e}")
242
+ internal_error = InternalError(f"Command execution error: {str(e)}")
243
+ return ErrorResult(
244
+ message=internal_error.message,
245
+ code=internal_error.code,
246
+ details={"original_error": str(e)},
247
+ )
248
+
249
+ @classmethod
250
+ def get_param_info(cls) -> Dict[str, Dict[str, Any]]:
251
+ """
252
+ Gets information about execute method parameters.
253
+
254
+ Returns:
255
+ Dictionary with parameters information.
256
+ """
257
+ signature = inspect.signature(cls.execute)
258
+ params = {}
259
+
260
+ for name, param in signature.parameters.items():
261
+ if name == "self":
262
+ continue
263
+
264
+ param_info = {
265
+ "name": name,
266
+ "required": param.default == inspect.Parameter.empty,
267
+ }
268
+
269
+ if param.annotation != inspect.Parameter.empty:
270
+ param_info["type"] = str(param.annotation)
271
+
272
+ if param.default != inspect.Parameter.empty:
273
+ param_info["default"] = param.default
274
+
275
+ params[name] = param_info
276
+
277
+ return params
278
+
279
+ @classmethod
280
+
281
+ @classmethod
282
+ def _generate_examples(
283
+ cls, params: Dict[str, Dict[str, Any]]
284
+ ) -> List[Dict[str, Any]]:
285
+ """
286
+ Generates usage examples of the command based on its parameters.
287
+
288
+ Args:
289
+ params: Information about command parameters
290
+
291
+ Returns:
292
+ List of examples
293
+ """
294
+ examples = []
295
+
296
+ # Simple example without parameters, if all parameters are optional
297
+ if not any(param.get("required", False) for param in params.values()):
298
+ examples.append(
299
+ {
300
+ "command": cls.name,
301
+ "description": f"Call {cls.name} command without parameters",
302
+ }
303
+ )
304
+
305
+ # Example with all required parameters
306
+ required_params = {k: v for k, v in params.items() if v.get("required", False)}
307
+ if required_params:
308
+ sample_params = {}
309
+ for param_name, param_info in required_params.items():
310
+ # Try to generate sample value based on type
311
+ param_type = param_info.get("type", "")
312
+
313
+ if "str" in param_type:
314
+ sample_params[param_name] = f"sample_{param_name}"
315
+ elif "int" in param_type:
316
+ sample_params[param_name] = 1
317
+ elif "float" in param_type:
318
+ sample_params[param_name] = 1.0
319
+ elif "bool" in param_type:
320
+ sample_params[param_name] = True
321
+ elif "list" in param_type or "List" in param_type:
322
+ sample_params[param_name] = []
323
+ elif "dict" in param_type or "Dict" in param_type:
324
+ sample_params[param_name] = {}
325
+ else:
326
+ sample_params[param_name] = "..."
327
+
328
+ examples.append(
329
+ {
330
+ "command": cls.name,
331
+ "params": sample_params,
332
+ "description": f"Call {cls.name} command with required parameters",
333
+ }
334
+ )
335
+
336
+ # Example with all parameters (including optional ones)
337
+ if len(params) > len(required_params):
338
+ all_params = {}
339
+ for param_name, param_info in params.items():
340
+ # For required parameters, use the same values as above
341
+ if param_info.get("required", False):
342
+ # Try to generate sample value based on type
343
+ param_type = param_info.get("type", "")
344
+
345
+ if "str" in param_type:
346
+ all_params[param_name] = f"sample_{param_name}"
347
+ elif "int" in param_type:
348
+ all_params[param_name] = 1
349
+ elif "float" in param_type:
350
+ all_params[param_name] = 1.0
351
+ elif "bool" in param_type:
352
+ all_params[param_name] = True
353
+ elif "list" in param_type or "List" in param_type:
354
+ all_params[param_name] = []
355
+ elif "dict" in param_type or "Dict" in param_type:
356
+ all_params[param_name] = {}
357
+ else:
358
+ all_params[param_name] = "..."
359
+ # For optional parameters, use their default values or a sample value
360
+ else:
361
+ if "default" in param_info:
362
+ all_params[param_name] = param_info["default"]
363
+ else:
364
+ param_type = param_info.get("type", "")
365
+
366
+ if "str" in param_type:
367
+ all_params[param_name] = f"optional_{param_name}"
368
+ elif "int" in param_type:
369
+ all_params[param_name] = 0
370
+ elif "float" in param_type:
371
+ all_params[param_name] = 0.0
372
+ elif "bool" in param_type:
373
+ all_params[param_name] = False
374
+ elif "list" in param_type or "List" in param_type:
375
+ all_params[param_name] = []
376
+ elif "dict" in param_type or "Dict" in param_type:
377
+ all_params[param_name] = {}
378
+ else:
379
+ all_params[param_name] = None
380
+
381
+ examples.append(
382
+ {
383
+ "command": cls.name,
384
+ "params": all_params,
385
+ "description": f"Call {cls.name} command with all parameters",
386
+ }
387
+ )
388
+
389
+ return examples
@@ -0,0 +1,30 @@
1
+ """
2
+ Module for registering built-in framework commands.
3
+
4
+ This module contains the procedure for adding predefined commands
5
+ that are part of the framework.
6
+ """
7
+
8
+ from typing import List
9
+ from mcp_proxy_adapter.commands.command_registry import registry
10
+ from mcp_proxy_adapter.commands.help_command import HelpCommand
11
+ from mcp_proxy_adapter.commands.health_command import HealthCommand
12
+ from mcp_proxy_adapter.commands.config_command import ConfigCommand
13
+ from mcp_proxy_adapter.commands.reload_command import ReloadCommand
14
+ from mcp_proxy_adapter.commands.settings_command import SettingsCommand
15
+ from mcp_proxy_adapter.commands.load_command import LoadCommand
16
+ from mcp_proxy_adapter.commands.unload_command import UnloadCommand
17
+ from mcp_proxy_adapter.commands.plugins_command import PluginsCommand
18
+ from mcp_proxy_adapter.commands.transport_management_command import (
19
+ TransportManagementCommand,
20
+ )
21
+ from mcp_proxy_adapter.commands.proxy_registration_command import (
22
+ ProxyRegistrationCommand,
23
+ )
24
+ from mcp_proxy_adapter.commands.echo_command import EchoCommand
25
+ from mcp_proxy_adapter.commands.role_test_command import RoleTestCommand
26
+ from mcp_proxy_adapter.core.logging import get_global_logger
27
+
28
+
29
+
30
+
@@ -0,0 +1,20 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Command catalog management package for MCP Proxy Adapter.
6
+ """
7
+
8
+ from .command_catalog import CommandCatalog
9
+ from .catalog_manager import CatalogManager
10
+ from .catalog_loader import CatalogLoader
11
+ from .catalog_syncer import CatalogSyncer
12
+ from .dependency_manager import DependencyManager
13
+
14
+ __all__ = [
15
+ "CommandCatalog",
16
+ "CatalogManager",
17
+ "CatalogLoader",
18
+ "CatalogSyncer",
19
+ "DependencyManager",
20
+ ]
@@ -0,0 +1,34 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Catalog loading utilities for MCP Proxy Adapter.
6
+ """
7
+
8
+ import json
9
+ from pathlib import Path
10
+
11
+ from mcp_proxy_adapter.core.logging import get_global_logger
12
+ from .command_catalog import CommandCatalog
13
+
14
+ # Try to import requests, but don't fail if not available
15
+ try:
16
+ import requests
17
+ REQUESTS_AVAILABLE = True
18
+ except ImportError:
19
+ REQUESTS_AVAILABLE = False
20
+ get_global_logger().warning(
21
+ "requests library not available, HTTP/HTTPS functionality will be limited"
22
+ )
23
+
24
+
25
+ class CatalogLoader:
26
+ """Loader for command catalogs from various sources."""
27
+
28
+ def __init__(self):
29
+ """Initialize catalog loader."""
30
+ self.logger = get_global_logger()
31
+
32
+
33
+
34
+
@@ -0,0 +1,122 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Main catalog manager for MCP Proxy Adapter.
6
+ """
7
+
8
+ import json
9
+ from pathlib import Path
10
+ from typing import Dict, List, Optional, Any
11
+ from packaging import version as pkg_version
12
+
13
+ from mcp_proxy_adapter.core.logging import get_global_logger
14
+ from mcp_proxy_adapter.commands.dependency_manager import dependency_manager
15
+ from mcp_proxy_adapter.config import config
16
+ from .command_catalog import CommandCatalog
17
+ from .catalog_loader import CatalogLoader
18
+ from .catalog_syncer import CatalogSyncer
19
+ from .dependency_manager import DependencyManager
20
+
21
+ # Try to import requests, but don't fail if not available
22
+ try:
23
+ import requests
24
+ REQUESTS_AVAILABLE = True
25
+ except ImportError:
26
+ REQUESTS_AVAILABLE = False
27
+ get_global_logger().warning(
28
+ "requests library not available, HTTP/HTTPS functionality will be limited"
29
+ )
30
+
31
+
32
+ class CatalogManager:
33
+ """
34
+ Manager for command catalog operations.
35
+
36
+ Handles loading, syncing, and managing command catalogs from various sources.
37
+ """
38
+
39
+ def __init__(self, catalog_dir: str):
40
+ """
41
+ Initialize catalog manager.
42
+
43
+ Args:
44
+ catalog_dir: Directory for catalog storage
45
+ """
46
+ self.catalog_dir = Path(catalog_dir)
47
+ self.logger = get_global_logger()
48
+
49
+ # Initialize components
50
+ self.loader = CatalogLoader()
51
+ self.syncer = CatalogSyncer(catalog_dir)
52
+ self.dependency_manager = DependencyManager()
53
+
54
+ # Load existing catalog
55
+ self.catalog: Dict[str, CommandCatalog] = {}
56
+ self._load_catalog()
57
+
58
+ def _load_catalog(self) -> None:
59
+ """Load catalog from local storage."""
60
+ catalog_file = self.catalog_dir / "catalog.json"
61
+ self.catalog = self.loader.load_catalog_from_file(catalog_file)
62
+
63
+ def _save_catalog(self) -> None:
64
+ """Save catalog to local storage."""
65
+ catalog_file = self.catalog_dir / "catalog.json"
66
+ self.loader.save_catalog_to_file(self.catalog, catalog_file)
67
+
68
+
69
+ def sync_with_servers(self, server_urls: List[str]) -> Dict[str, Any]:
70
+ """
71
+ Synchronize catalog with remote servers.
72
+
73
+ Args:
74
+ server_urls: List of server URLs to sync with
75
+
76
+ Returns:
77
+ Dictionary with sync results
78
+ """
79
+ return self.syncer.sync_with_servers(server_urls)
80
+
81
+
82
+
83
+
84
+
85
+ def _extract_metadata_from_file(self, file_path: str) -> Dict[str, Any]:
86
+ """
87
+ Extract metadata from command file.
88
+
89
+ Args:
90
+ file_path: Path to command file
91
+
92
+ Returns:
93
+ Dictionary of extracted metadata
94
+ """
95
+ metadata = {}
96
+
97
+ try:
98
+ with open(file_path, 'r', encoding='utf-8') as f:
99
+ content = f.read()
100
+
101
+ # Extract basic metadata
102
+ for line in content.split('\n'):
103
+ line = line.strip()
104
+ if line.startswith('__version__'):
105
+ metadata['version'] = line.split('=')[1].strip().strip('"\'')
106
+ elif line.startswith('__author__'):
107
+ metadata['author'] = line.split('=')[1].strip().strip('"\'')
108
+ elif line.startswith('__description__'):
109
+ metadata['description'] = line.split('=')[1].strip().strip('"\'')
110
+ elif line.startswith('__category__'):
111
+ metadata['category'] = line.split('=')[1].strip().strip('"\'')
112
+ elif line.startswith('__email__'):
113
+ metadata['email'] = line.split('=')[1].strip().strip('"\'')
114
+ elif line.startswith('__depends__'):
115
+ deps_str = line.split('=')[1].strip().strip('[]"\'')
116
+ if deps_str:
117
+ metadata['depends'] = [dep.strip().strip('"\'') for dep in deps_str.split(',')]
118
+
119
+ except Exception as e:
120
+ self.logger.error(f"Failed to extract metadata from {file_path}: {e}")
121
+
122
+ return metadata