mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.0.1__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 (212) hide show
  1. mcp_proxy_adapter/__main__.py +27 -7
  2. mcp_proxy_adapter/api/app.py +209 -79
  3. mcp_proxy_adapter/api/handlers.py +16 -5
  4. mcp_proxy_adapter/api/middleware/__init__.py +14 -9
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  7. mcp_proxy_adapter/api/middleware/protocol_middleware.py +84 -18
  8. mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
  9. mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
  10. mcp_proxy_adapter/commands/__init__.py +7 -1
  11. mcp_proxy_adapter/commands/base.py +7 -4
  12. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  13. mcp_proxy_adapter/commands/command_registry.py +8 -0
  14. mcp_proxy_adapter/commands/echo_command.py +81 -0
  15. mcp_proxy_adapter/commands/health_command.py +1 -1
  16. mcp_proxy_adapter/commands/help_command.py +21 -14
  17. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  18. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  19. mcp_proxy_adapter/commands/security_command.py +488 -0
  20. mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
  21. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  22. mcp_proxy_adapter/config.py +323 -40
  23. mcp_proxy_adapter/core/app_factory.py +410 -0
  24. mcp_proxy_adapter/core/app_runner.py +272 -0
  25. mcp_proxy_adapter/core/certificate_utils.py +291 -73
  26. mcp_proxy_adapter/core/client.py +574 -0
  27. mcp_proxy_adapter/core/client_manager.py +284 -0
  28. mcp_proxy_adapter/core/client_security.py +384 -0
  29. mcp_proxy_adapter/core/logging.py +8 -3
  30. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  31. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  32. mcp_proxy_adapter/core/protocol_manager.py +169 -10
  33. mcp_proxy_adapter/core/proxy_client.py +602 -0
  34. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  35. mcp_proxy_adapter/core/security_adapter.py +12 -15
  36. mcp_proxy_adapter/core/security_integration.py +286 -0
  37. mcp_proxy_adapter/core/server_adapter.py +282 -0
  38. mcp_proxy_adapter/core/server_engine.py +270 -0
  39. mcp_proxy_adapter/core/ssl_utils.py +13 -12
  40. mcp_proxy_adapter/core/transport_manager.py +5 -5
  41. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  42. mcp_proxy_adapter/examples/__init__.py +13 -4
  43. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  44. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  45. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  46. mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
  47. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  48. mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
  49. mcp_proxy_adapter/examples/debug_request_state.py +112 -0
  50. mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
  51. mcp_proxy_adapter/examples/demo_client.py +275 -0
  52. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  53. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  54. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  55. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  56. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  57. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  58. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  59. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  60. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  61. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  62. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  63. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  64. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  65. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  66. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  67. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
  68. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  69. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  70. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
  71. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  72. mcp_proxy_adapter/examples/full_application/main.py +173 -0
  73. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  74. mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
  75. mcp_proxy_adapter/examples/generate_certificates.py +177 -0
  76. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  77. mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
  78. mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
  79. mcp_proxy_adapter/examples/run_example.py +59 -0
  80. mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
  81. mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
  82. mcp_proxy_adapter/examples/run_security_tests.py +544 -0
  83. mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
  84. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  85. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  86. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  87. mcp_proxy_adapter/examples/security_test_client.py +782 -0
  88. mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
  89. mcp_proxy_adapter/examples/test_config.py +148 -0
  90. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  91. mcp_proxy_adapter/examples/test_examples.py +281 -0
  92. mcp_proxy_adapter/examples/universal_client.py +620 -0
  93. mcp_proxy_adapter/main.py +66 -148
  94. mcp_proxy_adapter/utils/config_generator.py +1008 -0
  95. mcp_proxy_adapter/version.py +5 -2
  96. mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
  97. mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
  98. mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
  99. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
  100. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  101. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  102. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  103. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  104. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  105. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  106. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  107. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  108. mcp_proxy_adapter/api/middleware/security.py +0 -376
  109. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  110. mcp_proxy_adapter/examples/README.md +0 -124
  111. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  112. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  113. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  114. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  115. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  116. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  117. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  118. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  119. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  120. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  121. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  122. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  123. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  124. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  125. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  126. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  127. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  128. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  129. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  130. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  131. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  132. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  133. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  134. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  135. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  136. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  137. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  138. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  139. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  140. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  141. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  142. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  143. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  144. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  145. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  146. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  147. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  148. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  149. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  150. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  151. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  152. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  153. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  154. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  155. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  156. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  157. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  158. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  159. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  160. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  161. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  162. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  163. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  164. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  165. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  166. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  167. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  168. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  169. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  170. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  171. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  172. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  173. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  174. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  175. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  176. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  177. mcp_proxy_adapter/tests/__init__.py +0 -0
  178. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  179. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  180. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  181. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  182. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  183. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  184. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  185. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  186. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  187. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  188. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  189. mcp_proxy_adapter/tests/conftest.py +0 -131
  190. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  191. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  192. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  193. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  194. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  195. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  196. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  197. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  198. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  199. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  200. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  201. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  202. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  203. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  204. mcp_proxy_adapter/tests/test_config.py +0 -127
  205. mcp_proxy_adapter/tests/test_utils.py +0 -65
  206. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  207. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  208. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  209. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  210. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  211. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
  212. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,158 @@
1
+ """
2
+ User Info Middleware
3
+
4
+ This middleware extracts user information from authentication headers
5
+ and sets it in request.state for use by commands.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import logging
12
+ from typing import Dict, Any, Optional, Callable, Awaitable
13
+ from fastapi import Request, Response
14
+ from starlette.middleware.base import BaseHTTPMiddleware
15
+
16
+ from mcp_proxy_adapter.core.logging import logger
17
+
18
+ # Import mcp_security_framework components
19
+ try:
20
+ from mcp_security_framework import AuthManager
21
+ from mcp_security_framework.schemas.config import AuthConfig
22
+ _MCP_SECURITY_AVAILABLE = True
23
+ print("✅ mcp_security_framework available in middleware")
24
+ except ImportError:
25
+ _MCP_SECURITY_AVAILABLE = False
26
+ print("⚠️ mcp_security_framework not available in middleware, using basic auth")
27
+
28
+
29
+ class UserInfoMiddleware(BaseHTTPMiddleware):
30
+ """
31
+ Middleware for setting user information in request.state.
32
+
33
+ This middleware extracts user information from authentication headers
34
+ and sets it in request.state for use by commands.
35
+ """
36
+
37
+ def __init__(self, app, config: Dict[str, Any]):
38
+ """
39
+ Initialize user info middleware.
40
+
41
+ Args:
42
+ app: FastAPI application
43
+ config: Configuration dictionary
44
+ """
45
+ super().__init__(app)
46
+ self.config = config
47
+
48
+ # Initialize AuthManager if available
49
+ self.auth_manager = None
50
+ self._security_available = _MCP_SECURITY_AVAILABLE
51
+
52
+ if self._security_available:
53
+ try:
54
+ # Get API keys configuration
55
+ security_config = config.get("security", {})
56
+ auth_config = security_config.get("auth", {})
57
+
58
+ # Create AuthConfig for mcp_security_framework
59
+ mcp_auth_config = AuthConfig(
60
+ enabled=True,
61
+ methods=["api_key"],
62
+ api_keys=auth_config.get("api_keys", {})
63
+ )
64
+
65
+ self.auth_manager = AuthManager(mcp_auth_config)
66
+ logger.info("✅ User info middleware initialized with mcp_security_framework")
67
+ except Exception as e:
68
+ logger.warning(f"⚠️ Failed to initialize AuthManager: {e}")
69
+ self._security_available = False
70
+
71
+ if not self._security_available:
72
+ # Fallback to basic API key handling
73
+ security_config = config.get("security", {})
74
+ auth_config = security_config.get("auth", {})
75
+ self.api_keys = auth_config.get("api_keys", {})
76
+ logger.info("ℹ️ User info middleware initialized with basic auth")
77
+
78
+ async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
79
+ """
80
+ Process request and set user info in request.state.
81
+
82
+ Args:
83
+ request: Request object
84
+ call_next: Next handler
85
+
86
+ Returns:
87
+ Response object
88
+ """
89
+ # Extract API key from headers
90
+ api_key = request.headers.get("X-API-Key")
91
+
92
+ if api_key:
93
+ if self.auth_manager and self._security_available:
94
+ try:
95
+ # Use mcp_security_framework AuthManager
96
+ auth_result = self.auth_manager.authenticate_api_key(api_key)
97
+
98
+ if auth_result.is_valid:
99
+ # Set user info from AuthManager result
100
+ request.state.user = {
101
+ "id": api_key,
102
+ "role": auth_result.roles[0] if auth_result.roles else "guest",
103
+ "roles": auth_result.roles or ["guest"],
104
+ "permissions": getattr(auth_result, 'permissions', ["read"])
105
+ }
106
+ logger.debug(f"✅ Authenticated user with mcp_security_framework: {request.state.user}")
107
+ else:
108
+ # Authentication failed
109
+ request.state.user = {
110
+ "id": None,
111
+ "role": "guest",
112
+ "roles": ["guest"],
113
+ "permissions": ["read"]
114
+ }
115
+ logger.debug(f"❌ Authentication failed for API key: {api_key[:8]}...")
116
+ except Exception as e:
117
+ logger.warning(f"⚠️ AuthManager error: {e}, falling back to basic auth")
118
+ self._security_available = False
119
+
120
+ if not self._security_available:
121
+ # Fallback to basic API key handling
122
+ if api_key in getattr(self, 'api_keys', {}):
123
+ user_role = self.api_keys[api_key]
124
+
125
+ # Get permissions for this role from roles file if available
126
+ role_permissions = ["read"] # default permissions
127
+ if hasattr(self, 'roles_config') and self.roles_config and user_role in self.roles_config:
128
+ role_permissions = self.roles_config[user_role].get("permissions", ["read"])
129
+
130
+ # Set user info in request.state
131
+ request.state.user = {
132
+ "id": api_key,
133
+ "role": user_role,
134
+ "roles": [user_role],
135
+ "permissions": role_permissions
136
+ }
137
+
138
+ logger.debug(f"✅ Authenticated user with basic auth: {request.state.user}")
139
+ else:
140
+ # API key not found
141
+ request.state.user = {
142
+ "id": None,
143
+ "role": "guest",
144
+ "roles": ["guest"],
145
+ "permissions": ["read"]
146
+ }
147
+ logger.debug(f"❌ API key not found: {api_key[:8]}...")
148
+ else:
149
+ # No API key provided - guest access
150
+ request.state.user = {
151
+ "id": None,
152
+ "role": "guest",
153
+ "roles": ["guest"],
154
+ "permissions": ["read"]
155
+ }
156
+ logger.debug("ℹ️ No API key provided, using guest access")
157
+
158
+ return await call_next(request)
@@ -12,6 +12,9 @@ from mcp_proxy_adapter.commands.certificate_management_command import Certificat
12
12
  from mcp_proxy_adapter.commands.key_management_command import KeyManagementCommand
13
13
  from mcp_proxy_adapter.commands.cert_monitor_command import CertMonitorCommand
14
14
  from mcp_proxy_adapter.commands.transport_management_command import TransportManagementCommand
15
+ from mcp_proxy_adapter.commands.role_test_command import RoleTestCommand
16
+ from mcp_proxy_adapter.commands.echo_command import EchoCommand
17
+ from mcp_proxy_adapter.commands.proxy_registration_command import ProxyRegistrationCommand
15
18
 
16
19
  __all__ = [
17
20
  "Command",
@@ -27,5 +30,8 @@ __all__ = [
27
30
  "CertificateManagementCommand",
28
31
  "KeyManagementCommand",
29
32
  "CertMonitorCommand",
30
- "TransportManagementCommand"
33
+ "TransportManagementCommand",
34
+ "RoleTestCommand",
35
+ "EchoCommand",
36
+ "ProxyRegistrationCommand"
31
37
  ]
@@ -48,7 +48,7 @@ class Command(ABC):
48
48
  Execute command with the specified parameters.
49
49
 
50
50
  Args:
51
- **kwargs: Command parameters.
51
+ **kwargs: Command parameters including optional 'context' parameter.
52
52
 
53
53
  Returns:
54
54
  Command result.
@@ -153,11 +153,14 @@ class Command(ABC):
153
153
  Runs the command with the specified arguments.
154
154
 
155
155
  Args:
156
- **kwargs: Command arguments.
156
+ **kwargs: Command arguments including optional 'context' parameter.
157
157
 
158
158
  Returns:
159
159
  Command result.
160
160
  """
161
+ # Extract context from kwargs
162
+ context = kwargs.pop('context', {}) if 'context' in kwargs else {}
163
+
161
164
  try:
162
165
  logger.debug(f"Running command {cls.__name__} with params: {kwargs}")
163
166
 
@@ -185,8 +188,8 @@ class Command(ABC):
185
188
  command = command_class()
186
189
  validated_params = command.validate_params(kwargs)
187
190
 
188
- # Execute command with validated parameters
189
- result = await command.execute(**validated_params)
191
+ # Execute command with validated parameters and context
192
+ result = await command.execute(**validated_params, context=context)
190
193
 
191
194
  logger.debug(f"Command {cls.__name__} executed successfully")
192
195
  return result
@@ -17,6 +17,8 @@ from mcp_proxy_adapter.commands.unload_command import UnloadCommand
17
17
  from mcp_proxy_adapter.commands.plugins_command import PluginsCommand
18
18
  from mcp_proxy_adapter.commands.transport_management_command import TransportManagementCommand
19
19
  from mcp_proxy_adapter.commands.proxy_registration_command import ProxyRegistrationCommand
20
+ from mcp_proxy_adapter.commands.echo_command import EchoCommand
21
+ from mcp_proxy_adapter.commands.role_test_command import RoleTestCommand
20
22
  from mcp_proxy_adapter.core.logging import logger
21
23
 
22
24
 
@@ -39,7 +41,9 @@ def register_builtin_commands() -> int:
39
41
  UnloadCommand,
40
42
  PluginsCommand,
41
43
  TransportManagementCommand,
42
- ProxyRegistrationCommand
44
+ ProxyRegistrationCommand,
45
+ EchoCommand,
46
+ RoleTestCommand
43
47
  ]
44
48
 
45
49
  registered_count = 0
@@ -85,5 +89,7 @@ def get_builtin_commands_list() -> list:
85
89
  UnloadCommand,
86
90
  PluginsCommand,
87
91
  TransportManagementCommand,
88
- ProxyRegistrationCommand
92
+ ProxyRegistrationCommand,
93
+ EchoCommand,
94
+ RoleTestCommand
89
95
  ]
@@ -660,6 +660,14 @@ class CommandRegistry:
660
660
  except Exception as e:
661
661
  logger.error(f"❌ Failed to initialize logging: {e}")
662
662
 
663
+ # Step 2.5: Reload protocol manager configuration
664
+ try:
665
+ from mcp_proxy_adapter.core.protocol_manager import protocol_manager
666
+ protocol_manager.reload_config()
667
+ logger.info("✅ Protocol manager configuration reloaded")
668
+ except Exception as e:
669
+ logger.error(f"❌ Failed to reload protocol manager: {e}")
670
+
663
671
  # Step 3: Clear all commands (always clear for consistency)
664
672
  self.clear()
665
673
 
@@ -0,0 +1,81 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Echo command for testing purposes.
6
+ """
7
+
8
+ import asyncio
9
+ from typing import Any, Dict, Optional
10
+
11
+ from mcp_proxy_adapter.commands.base import Command
12
+ from mcp_proxy_adapter.commands.result import SuccessResult
13
+
14
+
15
+ class EchoCommandResult(SuccessResult):
16
+ """Result for echo command."""
17
+
18
+ def __init__(self, message: str, timestamp: Optional[str] = None):
19
+ data = {"message": message}
20
+ if timestamp:
21
+ data["timestamp"] = timestamp
22
+ super().__init__(data=data, message=message)
23
+
24
+ @classmethod
25
+ def get_schema(cls) -> Dict[str, Any]:
26
+ """Get JSON schema for result."""
27
+ return {
28
+ "type": "object",
29
+ "properties": {
30
+ "success": {"type": "boolean"},
31
+ "data": {
32
+ "type": "object",
33
+ "properties": {
34
+ "message": {"type": "string"},
35
+ "timestamp": {"type": "string", "nullable": True}
36
+ }
37
+ },
38
+ "message": {"type": "string"}
39
+ },
40
+ "required": ["success", "data"]
41
+ }
42
+
43
+
44
+ class EchoCommand(Command):
45
+ """Echo command for testing purposes."""
46
+
47
+ name = "echo"
48
+ version = "1.0.0"
49
+ descr = "Echo command for testing"
50
+ category = "testing"
51
+ author = "Vasiliy Zdanovskiy"
52
+ email = "vasilyvz@gmail.com"
53
+ result_class = EchoCommandResult
54
+
55
+ async def execute(self, **kwargs) -> EchoCommandResult:
56
+ """Execute echo command."""
57
+ message = kwargs.get("message", "Hello, World!")
58
+ timestamp = kwargs.get("timestamp")
59
+
60
+ # Simulate some processing time
61
+ await asyncio.sleep(0.001)
62
+
63
+ return EchoCommandResult(message=message, timestamp=timestamp)
64
+
65
+ def get_schema(self) -> Dict[str, Any]:
66
+ """Get command schema."""
67
+ return {
68
+ "type": "object",
69
+ "properties": {
70
+ "message": {
71
+ "type": "string",
72
+ "description": "Message to echo",
73
+ "default": "Hello, World!"
74
+ },
75
+ "timestamp": {
76
+ "type": "string",
77
+ "description": "Optional timestamp",
78
+ "nullable": True
79
+ }
80
+ }
81
+ }
@@ -80,7 +80,7 @@ class HealthCommand(Command):
80
80
  name = "health"
81
81
  result_class = HealthResult
82
82
 
83
- async def execute(self) -> HealthResult:
83
+ async def execute(self, **kwargs) -> HealthResult:
84
84
  """
85
85
  Execute health command.
86
86
 
@@ -46,13 +46,15 @@ class HelpResult(CommandResult):
46
46
  if self.command_info is not None:
47
47
  logger.debug(f"HelpResult.to_dict: returning command_info for {self.command_info.get('name', 'unknown')}")
48
48
  # Делаем безопасное получение всех полей с дефолтными значениями
49
+ metadata = self.command_info.get("metadata", {})
50
+ schema = self.command_info.get("schema", {})
49
51
  return {
50
52
  "cmdname": self.command_info.get("name", "unknown"),
51
53
  "info": {
52
- "description": self.command_info.get("description", ""),
53
- "summary": self.command_info.get("summary", ""),
54
- "params": self.command_info.get("params", {}),
55
- "examples": self.command_info.get("examples", [])
54
+ "description": metadata.get("description", ""),
55
+ "summary": metadata.get("summary", ""),
56
+ "params": schema.get("properties", {}),
57
+ "examples": metadata.get("examples", [])
56
58
  }
57
59
  }
58
60
 
@@ -190,14 +192,16 @@ class HelpCommand(Command):
190
192
  if cmdname is not None and cmdname != "":
191
193
  logger.debug(f"Обработка запроса для конкретной команды: {cmdname}")
192
194
  try:
193
- # Get command metadata from registry
194
- command_metadata = registry.get_command_metadata(cmdname)
195
+ # Get command info from registry
196
+ command_info = registry.get_command_info(cmdname)
197
+ if command_info is None:
198
+ raise NotFoundError(f"Command '{cmdname}' not found")
195
199
  logger.debug(f"Получены метаданные для команды {cmdname}")
196
- return HelpResult(command_info=command_metadata)
200
+ return HelpResult(command_info=command_info)
197
201
  except NotFoundError:
198
202
  logger.warning(f"Команда '{cmdname}' не найдена")
199
203
  # Получаем список всех команд
200
- all_commands = list(registry.get_all_metadata().keys())
204
+ all_commands = list(registry.get_all_commands().keys())
201
205
  if all_commands:
202
206
  example_cmd = all_commands[0]
203
207
  example = {
@@ -218,9 +222,9 @@ class HelpCommand(Command):
218
222
  # Otherwise, return information about all available commands
219
223
  logger.debug("Обработка запроса для всех команд")
220
224
 
221
- # Get metadata for all commands
222
- all_metadata = registry.get_all_metadata()
223
- logger.debug(f"Получены метаданные для {len(all_metadata)} команд")
225
+ # Get info for all commands
226
+ all_commands_info = registry.get_all_commands_info()
227
+ logger.debug(f"Получены метаданные для {len(all_commands_info.get('commands', {}))} команд")
224
228
 
225
229
  # Prepare response format with tool metadata
226
230
  result = {
@@ -240,17 +244,20 @@ class HelpCommand(Command):
240
244
  }
241
245
 
242
246
  # Add brief information about commands
243
- for name, metadata in all_metadata.items():
247
+ commands_data = all_commands_info.get("commands", {})
248
+ for name, command_info in commands_data.items():
244
249
  try:
245
250
  logger.debug(f"Обработка метаданных команды {name}")
246
251
  # Безопасное получение параметров с проверкой на наличие ключей
252
+ metadata = command_info.get("metadata", {})
253
+ schema = command_info.get("schema", {})
247
254
  result["commands"][name] = {
248
255
  "summary": metadata.get("summary", ""),
249
- "params_count": len(metadata.get("params", {}))
256
+ "params_count": len(schema.get("properties", {}))
250
257
  }
251
258
  except Exception as e:
252
259
  logger.error(f"Ошибка при обработке метаданных команды {name}: {e}")
253
- logger.debug(f"Метаданные команды {name}: {metadata}")
260
+ logger.debug(f"Метаданные команды {name}: {command_info}")
254
261
  # Пропускаем проблемную команду
255
262
  continue
256
263