mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__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/__init__.py +9 -5
- mcp_proxy_adapter/__main__.py +1 -1
- mcp_proxy_adapter/api/app.py +227 -176
- mcp_proxy_adapter/api/handlers.py +68 -60
- mcp_proxy_adapter/api/middleware/__init__.py +7 -5
- mcp_proxy_adapter/api/middleware/base.py +19 -16
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
- mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
- mcp_proxy_adapter/api/middleware/factory.py +50 -52
- mcp_proxy_adapter/api/middleware/logging.py +46 -30
- mcp_proxy_adapter/api/middleware/performance.py +19 -16
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
- mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
- mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
- mcp_proxy_adapter/api/schemas.py +69 -43
- mcp_proxy_adapter/api/tool_integration.py +83 -63
- mcp_proxy_adapter/api/tools.py +60 -50
- mcp_proxy_adapter/commands/__init__.py +15 -6
- mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
- mcp_proxy_adapter/commands/base.py +108 -112
- mcp_proxy_adapter/commands/builtin_commands.py +28 -18
- mcp_proxy_adapter/commands/catalog_manager.py +394 -265
- mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
- mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
- mcp_proxy_adapter/commands/command_registry.py +275 -226
- mcp_proxy_adapter/commands/config_command.py +48 -33
- mcp_proxy_adapter/commands/dependency_container.py +22 -23
- mcp_proxy_adapter/commands/dependency_manager.py +65 -56
- mcp_proxy_adapter/commands/echo_command.py +15 -15
- mcp_proxy_adapter/commands/health_command.py +31 -29
- mcp_proxy_adapter/commands/help_command.py +97 -61
- mcp_proxy_adapter/commands/hooks.py +65 -49
- mcp_proxy_adapter/commands/key_management_command.py +148 -147
- mcp_proxy_adapter/commands/load_command.py +58 -40
- mcp_proxy_adapter/commands/plugins_command.py +80 -54
- mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
- mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
- mcp_proxy_adapter/commands/reload_command.py +43 -37
- mcp_proxy_adapter/commands/result.py +26 -33
- mcp_proxy_adapter/commands/role_test_command.py +26 -26
- mcp_proxy_adapter/commands/roles_management_command.py +176 -173
- mcp_proxy_adapter/commands/security_command.py +134 -122
- mcp_proxy_adapter/commands/settings_command.py +47 -56
- mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
- mcp_proxy_adapter/commands/token_management_command.py +129 -158
- mcp_proxy_adapter/commands/transport_management_command.py +41 -36
- mcp_proxy_adapter/commands/unload_command.py +42 -37
- mcp_proxy_adapter/config.py +36 -35
- mcp_proxy_adapter/core/__init__.py +19 -21
- mcp_proxy_adapter/core/app_factory.py +30 -9
- mcp_proxy_adapter/core/app_runner.py +81 -64
- mcp_proxy_adapter/core/auth_validator.py +176 -182
- mcp_proxy_adapter/core/certificate_utils.py +469 -426
- mcp_proxy_adapter/core/client.py +155 -126
- mcp_proxy_adapter/core/client_manager.py +60 -54
- mcp_proxy_adapter/core/client_security.py +120 -91
- mcp_proxy_adapter/core/config_converter.py +176 -143
- mcp_proxy_adapter/core/config_validator.py +12 -4
- mcp_proxy_adapter/core/crl_utils.py +21 -7
- mcp_proxy_adapter/core/errors.py +64 -20
- mcp_proxy_adapter/core/logging.py +34 -29
- mcp_proxy_adapter/core/mtls_asgi.py +29 -25
- mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
- mcp_proxy_adapter/core/protocol_manager.py +154 -104
- mcp_proxy_adapter/core/proxy_client.py +202 -144
- mcp_proxy_adapter/core/proxy_registration.py +7 -3
- mcp_proxy_adapter/core/role_utils.py +139 -125
- mcp_proxy_adapter/core/security_adapter.py +88 -77
- mcp_proxy_adapter/core/security_factory.py +50 -44
- mcp_proxy_adapter/core/security_integration.py +72 -24
- mcp_proxy_adapter/core/server_adapter.py +68 -64
- mcp_proxy_adapter/core/server_engine.py +71 -53
- mcp_proxy_adapter/core/settings.py +68 -58
- mcp_proxy_adapter/core/ssl_utils.py +69 -56
- mcp_proxy_adapter/core/transport_manager.py +72 -60
- mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
- mcp_proxy_adapter/core/utils.py +4 -2
- mcp_proxy_adapter/custom_openapi.py +107 -99
- mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
- mcp_proxy_adapter/examples/debug_request_state.py +38 -19
- mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
- mcp_proxy_adapter/examples/demo_client.py +48 -36
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
- mcp_proxy_adapter/examples/generate_certificates.py +31 -16
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
- mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
- mcp_proxy_adapter/examples/run_example.py +23 -5
- mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
- mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
- mcp_proxy_adapter/examples/run_security_tests.py +103 -41
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
- mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/security_test_client.py +196 -127
- mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
- mcp_proxy_adapter/examples/test_config.py +19 -4
- mcp_proxy_adapter/examples/test_config_generator.py +23 -7
- mcp_proxy_adapter/examples/test_examples.py +84 -56
- mcp_proxy_adapter/examples/universal_client.py +119 -62
- mcp_proxy_adapter/openapi.py +108 -115
- mcp_proxy_adapter/utils/config_generator.py +429 -274
- mcp_proxy_adapter/version.py +1 -2
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
- mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
- mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
- mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
- mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -4,12 +4,17 @@ Settings command for demonstrating configuration management.
|
|
4
4
|
|
5
5
|
from typing import Dict, Any, Optional
|
6
6
|
from mcp_proxy_adapter.commands.base import Command
|
7
|
-
from mcp_proxy_adapter.core.settings import
|
7
|
+
from mcp_proxy_adapter.core.settings import (
|
8
|
+
Settings,
|
9
|
+
get_setting,
|
10
|
+
set_setting,
|
11
|
+
reload_settings,
|
12
|
+
)
|
8
13
|
|
9
14
|
|
10
15
|
class SettingsResult:
|
11
16
|
"""Result class for settings command."""
|
12
|
-
|
17
|
+
|
13
18
|
def __init__(
|
14
19
|
self,
|
15
20
|
success: bool,
|
@@ -17,7 +22,7 @@ class SettingsResult:
|
|
17
22
|
key: Optional[str] = None,
|
18
23
|
value: Any = None,
|
19
24
|
all_settings: Optional[Dict[str, Any]] = None,
|
20
|
-
error_message: Optional[str] = None
|
25
|
+
error_message: Optional[str] = None,
|
21
26
|
):
|
22
27
|
self.success = success
|
23
28
|
self.operation = operation
|
@@ -25,14 +30,11 @@ class SettingsResult:
|
|
25
30
|
self.value = value
|
26
31
|
self.all_settings = all_settings
|
27
32
|
self.error_message = error_message
|
28
|
-
|
33
|
+
|
29
34
|
def to_dict(self) -> Dict[str, Any]:
|
30
35
|
"""Convert result to dictionary."""
|
31
|
-
result = {
|
32
|
-
|
33
|
-
"operation": self.operation
|
34
|
-
}
|
35
|
-
|
36
|
+
result = {"success": self.success, "operation": self.operation}
|
37
|
+
|
36
38
|
if self.key is not None:
|
37
39
|
result["key"] = self.key
|
38
40
|
if self.value is not None:
|
@@ -41,9 +43,9 @@ class SettingsResult:
|
|
41
43
|
result["all_settings"] = self.all_settings
|
42
44
|
if self.error_message is not None:
|
43
45
|
result["error_message"] = self.error_message
|
44
|
-
|
46
|
+
|
45
47
|
return result
|
46
|
-
|
48
|
+
|
47
49
|
@classmethod
|
48
50
|
def get_schema(cls) -> Dict[str, Any]:
|
49
51
|
"""Get schema for the result."""
|
@@ -52,119 +54,108 @@ class SettingsResult:
|
|
52
54
|
"properties": {
|
53
55
|
"success": {
|
54
56
|
"type": "boolean",
|
55
|
-
"description": "Whether the operation was successful"
|
57
|
+
"description": "Whether the operation was successful",
|
56
58
|
},
|
57
59
|
"operation": {
|
58
60
|
"type": "string",
|
59
61
|
"description": "Type of operation performed",
|
60
|
-
"enum": ["get", "set", "get_all", "reload"]
|
62
|
+
"enum": ["get", "set", "get_all", "reload"],
|
61
63
|
},
|
62
64
|
"key": {
|
63
65
|
"type": "string",
|
64
|
-
"description": "Configuration key (for get/set operations)"
|
66
|
+
"description": "Configuration key (for get/set operations)",
|
65
67
|
},
|
66
68
|
"value": {
|
67
69
|
"description": "Configuration value (for get/set operations)"
|
68
70
|
},
|
69
71
|
"all_settings": {
|
70
72
|
"type": "object",
|
71
|
-
"description": "All configuration settings (for get_all operation)"
|
73
|
+
"description": "All configuration settings (for get_all operation)",
|
72
74
|
},
|
73
75
|
"error_message": {
|
74
76
|
"type": "string",
|
75
|
-
"description": "Error message if operation failed"
|
76
|
-
}
|
77
|
+
"description": "Error message if operation failed",
|
78
|
+
},
|
77
79
|
},
|
78
|
-
"required": ["success", "operation"]
|
80
|
+
"required": ["success", "operation"],
|
79
81
|
}
|
80
82
|
|
81
83
|
|
82
84
|
class SettingsCommand(Command):
|
83
85
|
"""Command for managing framework settings."""
|
84
|
-
|
86
|
+
|
85
87
|
name = "settings"
|
86
88
|
description = "Manage framework settings and configuration"
|
87
|
-
|
89
|
+
|
88
90
|
async def execute(self, **params) -> SettingsResult:
|
89
91
|
"""
|
90
92
|
Execute settings command.
|
91
|
-
|
93
|
+
|
92
94
|
Args:
|
93
95
|
operation: Operation to perform (get, set, get_all, reload)
|
94
96
|
key: Configuration key (for get/set operations)
|
95
97
|
value: Configuration value (for set operation)
|
96
|
-
|
98
|
+
|
97
99
|
Returns:
|
98
100
|
SettingsResult with operation result
|
99
101
|
"""
|
100
102
|
try:
|
101
103
|
operation = params.get("operation", "get_all")
|
102
|
-
|
104
|
+
|
103
105
|
if operation == "get":
|
104
106
|
key = params.get("key")
|
105
107
|
if not key:
|
106
108
|
return SettingsResult(
|
107
109
|
success=False,
|
108
110
|
operation=operation,
|
109
|
-
error_message="Key is required for 'get' operation"
|
111
|
+
error_message="Key is required for 'get' operation",
|
110
112
|
)
|
111
|
-
|
113
|
+
|
112
114
|
value = get_setting(key)
|
113
115
|
return SettingsResult(
|
114
|
-
success=True,
|
115
|
-
operation=operation,
|
116
|
-
key=key,
|
117
|
-
value=value
|
116
|
+
success=True, operation=operation, key=key, value=value
|
118
117
|
)
|
119
|
-
|
118
|
+
|
120
119
|
elif operation == "set":
|
121
120
|
key = params.get("key")
|
122
121
|
value = params.get("value")
|
123
|
-
|
122
|
+
|
124
123
|
if not key:
|
125
124
|
return SettingsResult(
|
126
125
|
success=False,
|
127
126
|
operation=operation,
|
128
|
-
error_message="Key is required for 'set' operation"
|
127
|
+
error_message="Key is required for 'set' operation",
|
129
128
|
)
|
130
|
-
|
129
|
+
|
131
130
|
set_setting(key, value)
|
132
131
|
return SettingsResult(
|
133
|
-
success=True,
|
134
|
-
operation=operation,
|
135
|
-
key=key,
|
136
|
-
value=value
|
132
|
+
success=True, operation=operation, key=key, value=value
|
137
133
|
)
|
138
|
-
|
134
|
+
|
139
135
|
elif operation == "get_all":
|
140
136
|
all_settings = Settings.get_all_settings()
|
141
137
|
return SettingsResult(
|
142
|
-
success=True,
|
143
|
-
operation=operation,
|
144
|
-
all_settings=all_settings
|
138
|
+
success=True, operation=operation, all_settings=all_settings
|
145
139
|
)
|
146
|
-
|
140
|
+
|
147
141
|
elif operation == "reload":
|
148
142
|
reload_settings()
|
149
|
-
return SettingsResult(
|
150
|
-
|
151
|
-
operation=operation
|
152
|
-
)
|
153
|
-
|
143
|
+
return SettingsResult(success=True, operation=operation)
|
144
|
+
|
154
145
|
else:
|
155
146
|
return SettingsResult(
|
156
147
|
success=False,
|
157
148
|
operation=operation,
|
158
|
-
error_message=f"Unknown operation: {operation}. Supported operations: get, set, get_all, reload"
|
149
|
+
error_message=f"Unknown operation: {operation}. Supported operations: get, set, get_all, reload",
|
159
150
|
)
|
160
|
-
|
151
|
+
|
161
152
|
except Exception as e:
|
162
153
|
return SettingsResult(
|
163
154
|
success=False,
|
164
155
|
operation=params.get("operation", "unknown"),
|
165
|
-
error_message=str(e)
|
156
|
+
error_message=str(e),
|
166
157
|
)
|
167
|
-
|
158
|
+
|
168
159
|
@classmethod
|
169
160
|
def get_schema(cls) -> Dict[str, Any]:
|
170
161
|
"""Get schema for the command."""
|
@@ -175,16 +166,16 @@ class SettingsCommand(Command):
|
|
175
166
|
"type": "string",
|
176
167
|
"description": "Operation to perform",
|
177
168
|
"enum": ["get", "set", "get_all", "reload"],
|
178
|
-
"default": "get_all"
|
169
|
+
"default": "get_all",
|
179
170
|
},
|
180
171
|
"key": {
|
181
172
|
"type": "string",
|
182
|
-
"description": "Configuration key in dot notation (e.g., 'server.host', 'custom.feature_enabled')"
|
173
|
+
"description": "Configuration key in dot notation (e.g., 'server.host', 'custom.feature_enabled')",
|
183
174
|
},
|
184
175
|
"value": {
|
185
176
|
"description": "Configuration value to set (for 'set' operation)"
|
186
|
-
}
|
177
|
+
},
|
187
178
|
},
|
188
179
|
"required": ["operation"],
|
189
|
-
"additionalProperties": False
|
190
|
-
}
|
180
|
+
"additionalProperties": False,
|
181
|
+
}
|
@@ -16,6 +16,7 @@ try:
|
|
16
16
|
from mcp_security_framework.core.ssl_manager import SSLManager
|
17
17
|
from mcp_security_framework.schemas.config import SSLConfig
|
18
18
|
from mcp_security_framework.utils.cert_utils import validate_certificate_chain
|
19
|
+
|
19
20
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
20
21
|
except ImportError:
|
21
22
|
SECURITY_FRAMEWORK_AVAILABLE = False
|
@@ -30,10 +31,10 @@ logger = logging.getLogger(__name__)
|
|
30
31
|
class SSLSetupCommand(Command):
|
31
32
|
"""
|
32
33
|
SSL Setup Command
|
33
|
-
|
34
|
+
|
34
35
|
Handles SSL/TLS configuration and certificate management.
|
35
36
|
"""
|
36
|
-
|
37
|
+
|
37
38
|
# Command metadata
|
38
39
|
name = "ssl_setup"
|
39
40
|
version = "1.0.0"
|
@@ -43,28 +44,28 @@ class SSLSetupCommand(Command):
|
|
43
44
|
email = "team@mcp-proxy-adapter.com"
|
44
45
|
source_url = "https://github.com/mcp-proxy-adapter"
|
45
46
|
result_class = SuccessResult
|
46
|
-
|
47
|
+
|
47
48
|
def __init__(self):
|
48
49
|
"""Initialize SSL Setup Command."""
|
49
50
|
super().__init__()
|
50
|
-
|
51
|
+
|
51
52
|
async def execute(self, **kwargs) -> SuccessResult | ErrorResult:
|
52
53
|
"""
|
53
54
|
Execute SSL setup command.
|
54
|
-
|
55
|
+
|
55
56
|
Args:
|
56
57
|
params: Command parameters including:
|
57
58
|
- action: Operation to perform (get, set, update, reset, test)
|
58
59
|
- config_data: Configuration data for set/update actions
|
59
60
|
- cert_file: Certificate file path for testing
|
60
61
|
- key_file: Private key file path for testing
|
61
|
-
|
62
|
+
|
62
63
|
Returns:
|
63
64
|
SuccessResult or ErrorResult
|
64
65
|
"""
|
65
66
|
try:
|
66
67
|
action = kwargs.get("action", "get")
|
67
|
-
|
68
|
+
|
68
69
|
if action == "get":
|
69
70
|
return await self._get_ssl_config()
|
70
71
|
elif action == "set":
|
@@ -75,108 +76,96 @@ class SSLSetupCommand(Command):
|
|
75
76
|
return await self._reset_ssl_config()
|
76
77
|
elif action == "test":
|
77
78
|
return await self._test_ssl_config(
|
78
|
-
kwargs.get("cert_file"),
|
79
|
-
kwargs.get("key_file")
|
79
|
+
kwargs.get("cert_file"), kwargs.get("key_file")
|
80
80
|
)
|
81
81
|
else:
|
82
82
|
return ErrorResult(
|
83
83
|
message=f"Unknown action: {action}. Supported actions: get, set, update, reset, test"
|
84
84
|
)
|
85
|
-
|
85
|
+
|
86
86
|
except Exception as e:
|
87
87
|
logger.error(f"SSL setup command failed: {e}")
|
88
|
-
return ErrorResult(
|
89
|
-
|
90
|
-
)
|
91
|
-
|
88
|
+
return ErrorResult(message=f"SSL setup command failed: {str(e)}")
|
89
|
+
|
92
90
|
async def _get_ssl_config(self) -> SuccessResult | ErrorResult:
|
93
91
|
"""Get current SSL configuration."""
|
94
92
|
try:
|
95
93
|
config = Config()
|
96
94
|
ssl_config = config.get("ssl", {})
|
97
|
-
|
95
|
+
|
98
96
|
# Add framework information
|
99
97
|
ssl_config["framework_available"] = SECURITY_FRAMEWORK_AVAILABLE
|
100
|
-
|
101
|
-
return SuccessResult(
|
102
|
-
|
103
|
-
)
|
104
|
-
|
98
|
+
|
99
|
+
return SuccessResult(data={"ssl_config": ssl_config})
|
100
|
+
|
105
101
|
except Exception as e:
|
106
102
|
logger.error(f"Failed to get SSL config: {e}")
|
107
|
-
return ErrorResult(
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
103
|
+
return ErrorResult(message=f"Failed to get SSL config: {str(e)}")
|
104
|
+
|
105
|
+
async def _set_ssl_config(
|
106
|
+
self, config_data: Dict[str, Any]
|
107
|
+
) -> SuccessResult | ErrorResult:
|
112
108
|
"""Set SSL configuration."""
|
113
109
|
try:
|
114
110
|
if not isinstance(config_data, dict):
|
115
|
-
return ErrorResult(
|
116
|
-
|
117
|
-
)
|
118
|
-
|
111
|
+
return ErrorResult(message="Configuration data must be a dictionary")
|
112
|
+
|
119
113
|
# Validate configuration if mcp_security_framework is available
|
120
114
|
if SECURITY_FRAMEWORK_AVAILABLE:
|
121
115
|
try:
|
122
116
|
ssl_config = SSLConfig(**config_data)
|
123
117
|
config_data = ssl_config.dict()
|
124
118
|
except Exception as e:
|
125
|
-
return ErrorResult(
|
126
|
-
|
127
|
-
)
|
128
|
-
|
119
|
+
return ErrorResult(message=f"Invalid SSL configuration: {str(e)}")
|
120
|
+
|
129
121
|
# Update configuration
|
130
122
|
config = Config()
|
131
123
|
config.update_config({"ssl": config_data})
|
132
|
-
|
124
|
+
|
133
125
|
return SuccessResult(
|
134
126
|
data={"message": "SSL configuration updated", "ssl_config": config_data}
|
135
127
|
)
|
136
|
-
|
128
|
+
|
137
129
|
except Exception as e:
|
138
130
|
logger.error(f"Failed to set SSL config: {e}")
|
139
|
-
return ErrorResult(
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
131
|
+
return ErrorResult(message=f"Failed to set SSL config: {str(e)}")
|
132
|
+
|
133
|
+
async def _update_ssl_config(
|
134
|
+
self, config_data: Dict[str, Any]
|
135
|
+
) -> SuccessResult | ErrorResult:
|
144
136
|
"""Update SSL configuration."""
|
145
137
|
try:
|
146
138
|
if not isinstance(config_data, dict):
|
147
|
-
return ErrorResult(
|
148
|
-
|
149
|
-
)
|
150
|
-
|
139
|
+
return ErrorResult(message="Configuration data must be a dictionary")
|
140
|
+
|
151
141
|
config = Config()
|
152
142
|
current_config = config.get("ssl", {})
|
153
|
-
|
143
|
+
|
154
144
|
# Update with new data
|
155
145
|
current_config.update(config_data)
|
156
|
-
|
146
|
+
|
157
147
|
# Validate configuration if mcp_security_framework is available
|
158
148
|
if SECURITY_FRAMEWORK_AVAILABLE:
|
159
149
|
try:
|
160
150
|
ssl_config = SSLConfig(**current_config)
|
161
151
|
current_config = ssl_config.dict()
|
162
152
|
except Exception as e:
|
163
|
-
return ErrorResult(
|
164
|
-
|
165
|
-
)
|
166
|
-
|
153
|
+
return ErrorResult(message=f"Invalid SSL configuration: {str(e)}")
|
154
|
+
|
167
155
|
# Update configuration
|
168
156
|
config.update_config({"ssl": current_config})
|
169
|
-
|
157
|
+
|
170
158
|
return SuccessResult(
|
171
|
-
data={
|
159
|
+
data={
|
160
|
+
"message": "SSL configuration updated",
|
161
|
+
"ssl_config": current_config,
|
162
|
+
}
|
172
163
|
)
|
173
|
-
|
164
|
+
|
174
165
|
except Exception as e:
|
175
166
|
logger.error(f"Failed to update SSL config: {e}")
|
176
|
-
return ErrorResult(
|
177
|
-
|
178
|
-
)
|
179
|
-
|
167
|
+
return ErrorResult(message=f"Failed to update SSL config: {str(e)}")
|
168
|
+
|
180
169
|
async def _reset_ssl_config(self) -> SuccessResult | ErrorResult:
|
181
170
|
"""Reset SSL configuration to defaults."""
|
182
171
|
try:
|
@@ -187,30 +176,33 @@ class SSLSetupCommand(Command):
|
|
187
176
|
"ca_file": None,
|
188
177
|
"verify_mode": "CERT_REQUIRED",
|
189
178
|
"cipher_suites": [],
|
190
|
-
"framework_available": SECURITY_FRAMEWORK_AVAILABLE
|
179
|
+
"framework_available": SECURITY_FRAMEWORK_AVAILABLE,
|
191
180
|
}
|
192
|
-
|
181
|
+
|
193
182
|
config = Config()
|
194
183
|
config.update_config({"ssl": default_config})
|
195
|
-
|
184
|
+
|
196
185
|
return SuccessResult(
|
197
|
-
data={
|
186
|
+
data={
|
187
|
+
"message": "SSL configuration reset to defaults",
|
188
|
+
"ssl_config": default_config,
|
189
|
+
}
|
198
190
|
)
|
199
|
-
|
191
|
+
|
200
192
|
except Exception as e:
|
201
193
|
logger.error(f"Failed to reset SSL config: {e}")
|
202
|
-
return ErrorResult(
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
194
|
+
return ErrorResult(message=f"Failed to reset SSL config: {str(e)}")
|
195
|
+
|
196
|
+
async def _test_ssl_config(
|
197
|
+
self, cert_file: Optional[str], key_file: Optional[str]
|
198
|
+
) -> SuccessResult | ErrorResult:
|
207
199
|
"""
|
208
200
|
Test SSL configuration.
|
209
|
-
|
201
|
+
|
210
202
|
Args:
|
211
203
|
cert_file: Path to certificate file
|
212
204
|
key_file: Path to private key file
|
213
|
-
|
205
|
+
|
214
206
|
Returns:
|
215
207
|
SuccessResult or ErrorResult with test results
|
216
208
|
"""
|
@@ -219,49 +211,40 @@ class SSLSetupCommand(Command):
|
|
219
211
|
return ErrorResult(
|
220
212
|
message="Both cert_file and key_file are required for testing"
|
221
213
|
)
|
222
|
-
|
214
|
+
|
223
215
|
if SECURITY_FRAMEWORK_AVAILABLE:
|
224
216
|
return await self._test_ssl_config_with_framework(cert_file, key_file)
|
225
217
|
else:
|
226
218
|
return await self._test_ssl_config_fallback(cert_file, key_file)
|
227
|
-
|
219
|
+
|
228
220
|
except Exception as e:
|
229
221
|
logger.error(f"Failed to test SSL config: {e}")
|
230
|
-
return ErrorResult(
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
222
|
+
return ErrorResult(message=f"Failed to test SSL config: {str(e)}")
|
223
|
+
|
224
|
+
async def _test_ssl_config_with_framework(
|
225
|
+
self, cert_file: str, key_file: str
|
226
|
+
) -> SuccessResult | ErrorResult:
|
235
227
|
"""Test SSL configuration using mcp_security_framework."""
|
236
228
|
try:
|
237
229
|
# Create SSL manager
|
238
|
-
ssl_config = SSLConfig(
|
239
|
-
|
240
|
-
key_file=key_file,
|
241
|
-
enabled=True
|
242
|
-
)
|
243
|
-
|
230
|
+
ssl_config = SSLConfig(cert_file=cert_file, key_file=key_file, enabled=True)
|
231
|
+
|
244
232
|
ssl_manager = SSLManager(ssl_config)
|
245
|
-
|
233
|
+
|
246
234
|
# Test SSL context creation
|
247
235
|
context = ssl_manager.create_server_ssl_context()
|
248
|
-
|
236
|
+
|
249
237
|
details = {
|
250
238
|
"framework": "mcp_security_framework",
|
251
239
|
"certificate_loaded": True,
|
252
240
|
"private_key_loaded": True,
|
253
241
|
"context_created": True,
|
254
242
|
"cert_file": cert_file,
|
255
|
-
"key_file": key_file
|
243
|
+
"key_file": key_file,
|
256
244
|
}
|
257
|
-
|
258
|
-
return SuccessResult(
|
259
|
-
|
260
|
-
"success": True,
|
261
|
-
"details": details
|
262
|
-
}
|
263
|
-
)
|
264
|
-
|
245
|
+
|
246
|
+
return SuccessResult(data={"success": True, "details": details})
|
247
|
+
|
265
248
|
except Exception as e:
|
266
249
|
return ErrorResult(
|
267
250
|
message=f"SSL test failed: {str(e)}",
|
@@ -272,22 +255,24 @@ class SSLSetupCommand(Command):
|
|
272
255
|
"framework": "mcp_security_framework",
|
273
256
|
"certificate_loaded": False,
|
274
257
|
"private_key_loaded": False,
|
275
|
-
"context_created": False
|
276
|
-
}
|
277
|
-
}
|
258
|
+
"context_created": False,
|
259
|
+
},
|
260
|
+
},
|
278
261
|
)
|
279
|
-
|
280
|
-
async def _test_ssl_config_fallback(
|
262
|
+
|
263
|
+
async def _test_ssl_config_fallback(
|
264
|
+
self, cert_file: str, key_file: str
|
265
|
+
) -> SuccessResult | ErrorResult:
|
281
266
|
"""Test SSL configuration using fallback method."""
|
282
267
|
try:
|
283
268
|
# Create SSL context
|
284
269
|
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
285
270
|
context.check_hostname = False
|
286
271
|
context.verify_mode = ssl.CERT_NONE
|
287
|
-
|
272
|
+
|
288
273
|
# Load certificate and key
|
289
274
|
context.load_cert_chain(cert_file, key_file)
|
290
|
-
|
275
|
+
|
291
276
|
# Test basic SSL functionality
|
292
277
|
details = {
|
293
278
|
"framework": "fallback (ssl module)",
|
@@ -296,41 +281,36 @@ class SSLSetupCommand(Command):
|
|
296
281
|
"private_key_loaded": True,
|
297
282
|
"context_created": True,
|
298
283
|
"cert_file": cert_file,
|
299
|
-
"key_file": key_file
|
300
|
-
}
|
301
|
-
|
302
|
-
return SuccessResult(
|
303
|
-
data={
|
304
|
-
"success": True,
|
305
|
-
"details": details
|
284
|
+
"key_file": key_file,
|
306
285
|
}
|
307
|
-
|
308
|
-
|
286
|
+
|
287
|
+
return SuccessResult(data={"success": True, "details": details})
|
288
|
+
|
309
289
|
except Exception as e:
|
310
290
|
return ErrorResult(
|
311
291
|
message=f"SSL test failed: {str(e)}",
|
312
292
|
data={
|
313
|
-
|
314
|
-
|
315
|
-
|
293
|
+
"success": False,
|
294
|
+
"error": str(e),
|
295
|
+
"details": {
|
316
296
|
"framework": "fallback (ssl module)",
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
}
|
297
|
+
"ssl_version": ssl.OPENSSL_VERSION,
|
298
|
+
"certificate_loaded": False,
|
299
|
+
"private_key_loaded": False,
|
300
|
+
"context_created": False,
|
301
|
+
},
|
302
|
+
},
|
323
303
|
)
|
324
|
-
|
304
|
+
|
325
305
|
def to_dict(self) -> Dict[str, Any]:
|
326
306
|
"""Convert command to dictionary."""
|
327
307
|
return {
|
328
308
|
"name": self.name,
|
329
309
|
"description": self.description,
|
330
310
|
"version": self.version,
|
331
|
-
"framework_available": SECURITY_FRAMEWORK_AVAILABLE
|
311
|
+
"framework_available": SECURITY_FRAMEWORK_AVAILABLE,
|
332
312
|
}
|
333
|
-
|
313
|
+
|
334
314
|
@classmethod
|
335
315
|
def get_schema(cls) -> Dict[str, Any]:
|
336
316
|
"""Get command schema."""
|
@@ -340,7 +320,7 @@ class SSLSetupCommand(Command):
|
|
340
320
|
"action": {
|
341
321
|
"type": "string",
|
342
322
|
"enum": ["get", "set", "update", "reset", "test"],
|
343
|
-
"description": "Action to perform"
|
323
|
+
"description": "Action to perform",
|
344
324
|
},
|
345
325
|
"config_data": {
|
346
326
|
"type": "object",
|
@@ -351,17 +331,17 @@ class SSLSetupCommand(Command):
|
|
351
331
|
"key_file": {"type": "string"},
|
352
332
|
"ca_file": {"type": "string"},
|
353
333
|
"verify_mode": {"type": "string"},
|
354
|
-
"cipher_suites": {"type": "array", "items": {"type": "string"}}
|
355
|
-
}
|
334
|
+
"cipher_suites": {"type": "array", "items": {"type": "string"}},
|
335
|
+
},
|
356
336
|
},
|
357
337
|
"cert_file": {
|
358
338
|
"type": "string",
|
359
|
-
"description": "Certificate file path for testing"
|
339
|
+
"description": "Certificate file path for testing",
|
360
340
|
},
|
361
341
|
"key_file": {
|
362
342
|
"type": "string",
|
363
|
-
"description": "Private key file path for testing"
|
364
|
-
}
|
343
|
+
"description": "Private key file path for testing",
|
344
|
+
},
|
365
345
|
},
|
366
|
-
"required": ["action"]
|
367
|
-
|
346
|
+
"required": ["action"],
|
347
|
+
}
|