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.
Files changed (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {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 Settings, get_setting, set_setting, reload_settings
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
- "success": self.success,
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
- success=True,
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
- message=f"SSL setup command failed: {str(e)}"
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
- data={"ssl_config": ssl_config}
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
- message=f"Failed to get SSL config: {str(e)}"
109
- )
110
-
111
- async def _set_ssl_config(self, config_data: Dict[str, Any]) -> SuccessResult | ErrorResult:
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
- message="Configuration data must be a dictionary"
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
- message=f"Invalid SSL configuration: {str(e)}"
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
- message=f"Failed to set SSL config: {str(e)}"
141
- )
142
-
143
- async def _update_ssl_config(self, config_data: Dict[str, Any]) -> SuccessResult | ErrorResult:
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
- message="Configuration data must be a dictionary"
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
- message=f"Invalid SSL configuration: {str(e)}"
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={"message": "SSL configuration updated", "ssl_config": current_config}
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
- message=f"Failed to update SSL config: {str(e)}"
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={"message": "SSL configuration reset to defaults", "ssl_config": default_config}
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
- message=f"Failed to reset SSL config: {str(e)}"
204
- )
205
-
206
- async def _test_ssl_config(self, cert_file: Optional[str], key_file: Optional[str]) -> SuccessResult | ErrorResult:
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
- message=f"Failed to test SSL config: {str(e)}"
232
- )
233
-
234
- async def _test_ssl_config_with_framework(self, cert_file: str, key_file: str) -> SuccessResult | ErrorResult:
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
- cert_file=cert_file,
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
- data={
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(self, cert_file: str, key_file: str) -> SuccessResult | ErrorResult:
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
- "success": False,
314
- "error": str(e),
315
- "details": {
293
+ "success": False,
294
+ "error": str(e),
295
+ "details": {
316
296
  "framework": "fallback (ssl module)",
317
- "ssl_version": ssl.OPENSSL_VERSION,
318
- "certificate_loaded": False,
319
- "private_key_loaded": False,
320
- "context_created": False
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
+ }