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.
- mcp_proxy_adapter/__main__.py +27 -7
- mcp_proxy_adapter/api/app.py +209 -79
- mcp_proxy_adapter/api/handlers.py +16 -5
- mcp_proxy_adapter/api/middleware/__init__.py +14 -9
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
- mcp_proxy_adapter/api/middleware/factory.py +36 -12
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +84 -18
- mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
- mcp_proxy_adapter/commands/__init__.py +7 -1
- mcp_proxy_adapter/commands/base.py +7 -4
- mcp_proxy_adapter/commands/builtin_commands.py +8 -2
- mcp_proxy_adapter/commands/command_registry.py +8 -0
- mcp_proxy_adapter/commands/echo_command.py +81 -0
- mcp_proxy_adapter/commands/health_command.py +1 -1
- mcp_proxy_adapter/commands/help_command.py +21 -14
- mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
- mcp_proxy_adapter/commands/role_test_command.py +141 -0
- mcp_proxy_adapter/commands/security_command.py +488 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
- mcp_proxy_adapter/commands/token_management_command.py +1 -1
- mcp_proxy_adapter/config.py +323 -40
- mcp_proxy_adapter/core/app_factory.py +410 -0
- mcp_proxy_adapter/core/app_runner.py +272 -0
- mcp_proxy_adapter/core/certificate_utils.py +291 -73
- mcp_proxy_adapter/core/client.py +574 -0
- mcp_proxy_adapter/core/client_manager.py +284 -0
- mcp_proxy_adapter/core/client_security.py +384 -0
- mcp_proxy_adapter/core/logging.py +8 -3
- mcp_proxy_adapter/core/mtls_asgi.py +156 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/protocol_manager.py +169 -10
- mcp_proxy_adapter/core/proxy_client.py +602 -0
- mcp_proxy_adapter/core/proxy_registration.py +299 -47
- mcp_proxy_adapter/core/security_adapter.py +12 -15
- mcp_proxy_adapter/core/security_integration.py +286 -0
- mcp_proxy_adapter/core/server_adapter.py +282 -0
- mcp_proxy_adapter/core/server_engine.py +270 -0
- mcp_proxy_adapter/core/ssl_utils.py +13 -12
- mcp_proxy_adapter/core/transport_manager.py +5 -5
- mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
- mcp_proxy_adapter/examples/__init__.py +13 -4
- mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
- mcp_proxy_adapter/examples/debug_request_state.py +112 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
- mcp_proxy_adapter/examples/demo_client.py +275 -0
- mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
- mcp_proxy_adapter/examples/generate_certificates.py +177 -0
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
- mcp_proxy_adapter/examples/run_example.py +59 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
- mcp_proxy_adapter/examples/run_security_tests.py +544 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
- mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/security_test_client.py +782 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
- mcp_proxy_adapter/examples/test_config.py +148 -0
- mcp_proxy_adapter/examples/test_config_generator.py +86 -0
- mcp_proxy_adapter/examples/test_examples.py +281 -0
- mcp_proxy_adapter/examples/universal_client.py +620 -0
- mcp_proxy_adapter/main.py +66 -148
- mcp_proxy_adapter/utils/config_generator.py +1008 -0
- mcp_proxy_adapter/version.py +5 -2
- mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
- mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
- mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
- mcp_proxy_adapter/api/middleware/auth.py +0 -146
- mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
- mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
- mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
- mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
- mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
- mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
- mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
- mcp_proxy_adapter/api/middleware/security.py +0 -376
- mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
- mcp_proxy_adapter/examples/README.md +0 -124
- mcp_proxy_adapter/examples/basic_server/README.md +0 -60
- mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
- mcp_proxy_adapter/examples/basic_server/config.json +0 -70
- mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
- mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
- mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
- mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
- mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
- mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
- mcp_proxy_adapter/examples/basic_server/server.py +0 -114
- mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
- mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
- mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
- mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
- mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
- mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
- mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
- mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
- mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
- mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
- mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
- mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
- mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
- mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
- mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
- mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
- mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
- mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
- mcp_proxy_adapter/examples/deployment/README.md +0 -49
- mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
- mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
- mcp_proxy_adapter/examples/deployment/config.json +0 -29
- mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
- mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
- mcp_proxy_adapter/examples/deployment/run.sh +0 -43
- mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
- mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
- mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
- mcp_proxy_adapter/schemas/base_schema.json +0 -114
- mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
- mcp_proxy_adapter/schemas/roles_schema.json +0 -162
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +0 -3
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
- mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
- mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
- mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
- mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
- mcp_proxy_adapter/tests/commands/__init__.py +0 -3
- mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
- mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
- mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
- mcp_proxy_adapter/tests/conftest.py +0 -131
- mcp_proxy_adapter/tests/functional/__init__.py +0 -3
- mcp_proxy_adapter/tests/functional/test_api.py +0 -253
- mcp_proxy_adapter/tests/integration/__init__.py +0 -3
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
- mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
- mcp_proxy_adapter/tests/performance/__init__.py +0 -3
- mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
- mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
- mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
- mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
- mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
- mcp_proxy_adapter/tests/test_base_command.py +0 -123
- mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
- mcp_proxy_adapter/tests/test_command_registry.py +0 -281
- mcp_proxy_adapter/tests/test_config.py +0 -127
- mcp_proxy_adapter/tests/test_utils.py +0 -65
- mcp_proxy_adapter/tests/unit/__init__.py +0 -3
- mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
- mcp_proxy_adapter/tests/unit/test_config.py +0 -270
- mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
- mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
- {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
|
+
}
|
@@ -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":
|
53
|
-
"summary":
|
54
|
-
"params":
|
55
|
-
"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
|
194
|
-
|
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=
|
200
|
+
return HelpResult(command_info=command_info)
|
197
201
|
except NotFoundError:
|
198
202
|
logger.warning(f"Команда '{cmdname}' не найдена")
|
199
203
|
# Получаем список всех команд
|
200
|
-
all_commands = list(registry.
|
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
|
222
|
-
|
223
|
-
logger.debug(f"Получены метаданные для {len(
|
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
|
-
|
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(
|
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}: {
|
260
|
+
logger.debug(f"Метаданные команды {name}: {command_info}")
|
254
261
|
# Пропускаем проблемную команду
|
255
262
|
continue
|
256
263
|
|