mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.5__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 +108 -88
- 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.5.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.5.dist-info/RECORD +143 -0
- mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -16,19 +16,19 @@ from mcp_proxy_adapter.core.logging import logger
|
|
16
16
|
class ConfigConverter:
|
17
17
|
"""
|
18
18
|
Converter for configuration formats.
|
19
|
-
|
19
|
+
|
20
20
|
Provides methods to convert between mcp_proxy_adapter configuration
|
21
21
|
and mcp_security_framework configuration formats.
|
22
22
|
"""
|
23
|
-
|
23
|
+
|
24
24
|
@staticmethod
|
25
25
|
def to_security_framework_config(mcp_config: Dict[str, Any]) -> Dict[str, Any]:
|
26
26
|
"""
|
27
27
|
Convert mcp_proxy_adapter configuration to SecurityConfig format.
|
28
|
-
|
28
|
+
|
29
29
|
Args:
|
30
30
|
mcp_config: mcp_proxy_adapter configuration dictionary
|
31
|
-
|
31
|
+
|
32
32
|
Returns:
|
33
33
|
SecurityConfig compatible dictionary
|
34
34
|
"""
|
@@ -40,7 +40,7 @@ class ConfigConverter:
|
|
40
40
|
"methods": ["api_key"],
|
41
41
|
"api_keys": {},
|
42
42
|
"jwt_secret": "",
|
43
|
-
"jwt_algorithm": "HS256"
|
43
|
+
"jwt_algorithm": "HS256",
|
44
44
|
},
|
45
45
|
"ssl": {
|
46
46
|
"enabled": False,
|
@@ -49,13 +49,13 @@ class ConfigConverter:
|
|
49
49
|
"ca_cert": None,
|
50
50
|
"min_tls_version": "TLSv1.2",
|
51
51
|
"verify_client": False,
|
52
|
-
"client_cert_required": False
|
52
|
+
"client_cert_required": False,
|
53
53
|
},
|
54
54
|
"permissions": {
|
55
55
|
"enabled": True,
|
56
56
|
"roles_file": "roles.json",
|
57
57
|
"default_role": "user",
|
58
|
-
"deny_by_default": True
|
58
|
+
"deny_by_default": True,
|
59
59
|
},
|
60
60
|
"rate_limit": {
|
61
61
|
"enabled": True,
|
@@ -63,113 +63,146 @@ class ConfigConverter:
|
|
63
63
|
"requests_per_hour": 1000,
|
64
64
|
"burst_limit": 10,
|
65
65
|
"by_ip": True,
|
66
|
-
"by_user": True
|
67
|
-
}
|
66
|
+
"by_user": True,
|
67
|
+
},
|
68
68
|
}
|
69
|
-
|
69
|
+
|
70
70
|
# Convert from security section if exists
|
71
71
|
if "security" in mcp_config:
|
72
72
|
security_section = mcp_config["security"]
|
73
|
-
|
73
|
+
|
74
74
|
# Convert auth config
|
75
75
|
if "auth" in security_section:
|
76
76
|
auth_config = security_section["auth"]
|
77
|
-
security_config["auth"].update(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
77
|
+
security_config["auth"].update(
|
78
|
+
{
|
79
|
+
"enabled": auth_config.get("enabled", True),
|
80
|
+
"methods": auth_config.get("methods", ["api_key"]),
|
81
|
+
"api_keys": auth_config.get("api_keys", {}),
|
82
|
+
"jwt_secret": auth_config.get("jwt_secret", ""),
|
83
|
+
"jwt_algorithm": auth_config.get("jwt_algorithm", "HS256"),
|
84
|
+
}
|
85
|
+
)
|
86
|
+
|
85
87
|
# Convert SSL config
|
86
88
|
if "ssl" in security_section:
|
87
89
|
ssl_config = security_section["ssl"]
|
88
|
-
security_config["ssl"].update(
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
security_config["ssl"].update(
|
91
|
+
{
|
92
|
+
"enabled": ssl_config.get("enabled", False),
|
93
|
+
"cert_file": ssl_config.get("cert_file"),
|
94
|
+
"key_file": ssl_config.get("key_file"),
|
95
|
+
"ca_cert": ssl_config.get("ca_cert"),
|
96
|
+
"min_tls_version": ssl_config.get(
|
97
|
+
"min_tls_version", "TLSv1.2"
|
98
|
+
),
|
99
|
+
"verify_client": ssl_config.get("verify_client", False),
|
100
|
+
"client_cert_required": ssl_config.get(
|
101
|
+
"client_cert_required", False
|
102
|
+
),
|
103
|
+
}
|
104
|
+
)
|
105
|
+
|
98
106
|
# Convert permissions config
|
99
107
|
if "permissions" in security_section:
|
100
108
|
permissions_config = security_section["permissions"]
|
101
|
-
security_config["permissions"].update(
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
109
|
+
security_config["permissions"].update(
|
110
|
+
{
|
111
|
+
"enabled": permissions_config.get("enabled", True),
|
112
|
+
"roles_file": permissions_config.get(
|
113
|
+
"roles_file", "roles.json"
|
114
|
+
),
|
115
|
+
"default_role": permissions_config.get(
|
116
|
+
"default_role", "user"
|
117
|
+
),
|
118
|
+
"deny_by_default": permissions_config.get(
|
119
|
+
"deny_by_default", True
|
120
|
+
),
|
121
|
+
}
|
122
|
+
)
|
123
|
+
|
108
124
|
# Convert rate limit config
|
109
125
|
if "rate_limit" in security_section:
|
110
126
|
rate_limit_config = security_section["rate_limit"]
|
111
|
-
security_config["rate_limit"].update(
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
127
|
+
security_config["rate_limit"].update(
|
128
|
+
{
|
129
|
+
"enabled": rate_limit_config.get("enabled", True),
|
130
|
+
"requests_per_minute": rate_limit_config.get(
|
131
|
+
"requests_per_minute", 60
|
132
|
+
),
|
133
|
+
"requests_per_hour": rate_limit_config.get(
|
134
|
+
"requests_per_hour", 1000
|
135
|
+
),
|
136
|
+
"burst_limit": rate_limit_config.get("burst_limit", 10),
|
137
|
+
"by_ip": rate_limit_config.get("by_ip", True),
|
138
|
+
"by_user": rate_limit_config.get("by_user", True),
|
139
|
+
}
|
140
|
+
)
|
141
|
+
|
120
142
|
# Convert from legacy SSL config if security section doesn't exist
|
121
143
|
elif "ssl" in mcp_config:
|
122
144
|
ssl_config = mcp_config["ssl"]
|
123
|
-
security_config["ssl"].update(
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
145
|
+
security_config["ssl"].update(
|
146
|
+
{
|
147
|
+
"enabled": ssl_config.get("enabled", False),
|
148
|
+
"cert_file": ssl_config.get("cert_file"),
|
149
|
+
"key_file": ssl_config.get("key_file"),
|
150
|
+
"ca_cert": ssl_config.get("ca_cert"),
|
151
|
+
"min_tls_version": ssl_config.get("min_tls_version", "TLSv1.2"),
|
152
|
+
"verify_client": ssl_config.get("verify_client", False),
|
153
|
+
"client_cert_required": ssl_config.get(
|
154
|
+
"client_cert_required", False
|
155
|
+
),
|
156
|
+
}
|
157
|
+
)
|
158
|
+
|
133
159
|
# Extract API keys from legacy SSL config
|
134
160
|
if "api_keys" in ssl_config:
|
135
161
|
security_config["auth"]["api_keys"] = ssl_config["api_keys"]
|
136
|
-
|
162
|
+
|
137
163
|
# Convert from legacy roles config
|
138
164
|
if "roles" in mcp_config:
|
139
165
|
roles_config = mcp_config["roles"]
|
140
|
-
security_config["permissions"].update(
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
166
|
+
security_config["permissions"].update(
|
167
|
+
{
|
168
|
+
"enabled": roles_config.get("enabled", True),
|
169
|
+
"roles_file": roles_config.get("config_file", "roles.json"),
|
170
|
+
"default_role": "user",
|
171
|
+
"deny_by_default": roles_config.get("default_policy", {}).get(
|
172
|
+
"deny_by_default", True
|
173
|
+
),
|
174
|
+
}
|
175
|
+
)
|
176
|
+
|
177
|
+
logger.info(
|
178
|
+
"Configuration converted to security framework format successfully"
|
179
|
+
)
|
148
180
|
return security_config
|
149
|
-
|
181
|
+
|
150
182
|
except Exception as e:
|
151
|
-
logger.error(
|
183
|
+
logger.error(
|
184
|
+
f"Failed to convert configuration to security framework format: {e}"
|
185
|
+
)
|
152
186
|
return ConfigConverter._get_default_security_config()
|
153
|
-
|
187
|
+
|
154
188
|
@staticmethod
|
155
|
-
def from_security_framework_config(
|
189
|
+
def from_security_framework_config(
|
190
|
+
security_config: Dict[str, Any]
|
191
|
+
) -> Dict[str, Any]:
|
156
192
|
"""
|
157
193
|
Convert SecurityConfig format to mcp_proxy_adapter configuration.
|
158
|
-
|
194
|
+
|
159
195
|
Args:
|
160
196
|
security_config: SecurityConfig compatible dictionary
|
161
|
-
|
197
|
+
|
162
198
|
Returns:
|
163
199
|
mcp_proxy_adapter configuration dictionary
|
164
200
|
"""
|
165
201
|
try:
|
166
202
|
mcp_config = {
|
167
|
-
"security": {
|
168
|
-
"framework": "mcp_security_framework",
|
169
|
-
"enabled": True
|
170
|
-
}
|
203
|
+
"security": {"framework": "mcp_security_framework", "enabled": True}
|
171
204
|
}
|
172
|
-
|
205
|
+
|
173
206
|
# Convert auth config
|
174
207
|
if "auth" in security_config:
|
175
208
|
auth_config = security_config["auth"]
|
@@ -178,9 +211,9 @@ class ConfigConverter:
|
|
178
211
|
"methods": auth_config.get("methods", ["api_key"]),
|
179
212
|
"api_keys": auth_config.get("api_keys", {}),
|
180
213
|
"jwt_secret": auth_config.get("jwt_secret", ""),
|
181
|
-
"jwt_algorithm": auth_config.get("jwt_algorithm", "HS256")
|
214
|
+
"jwt_algorithm": auth_config.get("jwt_algorithm", "HS256"),
|
182
215
|
}
|
183
|
-
|
216
|
+
|
184
217
|
# Convert SSL config
|
185
218
|
if "ssl" in security_config:
|
186
219
|
ssl_config = security_config["ssl"]
|
@@ -191,9 +224,11 @@ class ConfigConverter:
|
|
191
224
|
"ca_cert": ssl_config.get("ca_cert"),
|
192
225
|
"min_tls_version": ssl_config.get("min_tls_version", "TLSv1.2"),
|
193
226
|
"verify_client": ssl_config.get("verify_client", False),
|
194
|
-
"client_cert_required": ssl_config.get(
|
227
|
+
"client_cert_required": ssl_config.get(
|
228
|
+
"client_cert_required", False
|
229
|
+
),
|
195
230
|
}
|
196
|
-
|
231
|
+
|
197
232
|
# Convert permissions config
|
198
233
|
if "permissions" in security_config:
|
199
234
|
permissions_config = security_config["permissions"]
|
@@ -201,74 +236,84 @@ class ConfigConverter:
|
|
201
236
|
"enabled": permissions_config.get("enabled", True),
|
202
237
|
"roles_file": permissions_config.get("roles_file", "roles.json"),
|
203
238
|
"default_role": permissions_config.get("default_role", "user"),
|
204
|
-
"deny_by_default": permissions_config.get("deny_by_default", True)
|
239
|
+
"deny_by_default": permissions_config.get("deny_by_default", True),
|
205
240
|
}
|
206
|
-
|
241
|
+
|
207
242
|
# Convert rate limit config
|
208
243
|
if "rate_limit" in security_config:
|
209
244
|
rate_limit_config = security_config["rate_limit"]
|
210
245
|
mcp_config["security"]["rate_limit"] = {
|
211
246
|
"enabled": rate_limit_config.get("enabled", True),
|
212
|
-
"requests_per_minute": rate_limit_config.get(
|
213
|
-
|
247
|
+
"requests_per_minute": rate_limit_config.get(
|
248
|
+
"requests_per_minute", 60
|
249
|
+
),
|
250
|
+
"requests_per_hour": rate_limit_config.get(
|
251
|
+
"requests_per_hour", 1000
|
252
|
+
),
|
214
253
|
"burst_limit": rate_limit_config.get("burst_limit", 10),
|
215
254
|
"by_ip": rate_limit_config.get("by_ip", True),
|
216
|
-
"by_user": rate_limit_config.get("by_user", True)
|
255
|
+
"by_user": rate_limit_config.get("by_user", True),
|
217
256
|
}
|
218
|
-
|
219
|
-
logger.info(
|
257
|
+
|
258
|
+
logger.info(
|
259
|
+
"Configuration converted from security framework format successfully"
|
260
|
+
)
|
220
261
|
return mcp_config
|
221
|
-
|
262
|
+
|
222
263
|
except Exception as e:
|
223
|
-
logger.error(
|
264
|
+
logger.error(
|
265
|
+
f"Failed to convert configuration from security framework format: {e}"
|
266
|
+
)
|
224
267
|
return ConfigConverter._get_default_mcp_config()
|
225
|
-
|
268
|
+
|
226
269
|
@staticmethod
|
227
|
-
def migrate_legacy_config(
|
270
|
+
def migrate_legacy_config(
|
271
|
+
config_path: str, output_path: Optional[str] = None
|
272
|
+
) -> bool:
|
228
273
|
"""
|
229
274
|
Migrate legacy configuration to new security framework format.
|
230
|
-
|
275
|
+
|
231
276
|
Args:
|
232
277
|
config_path: Path to legacy configuration file
|
233
278
|
output_path: Path to output migrated configuration file (optional)
|
234
|
-
|
279
|
+
|
235
280
|
Returns:
|
236
281
|
True if migration successful, False otherwise
|
237
282
|
"""
|
238
283
|
try:
|
239
284
|
# Read legacy configuration
|
240
|
-
with open(config_path,
|
285
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
241
286
|
legacy_config = json.load(f)
|
242
|
-
|
287
|
+
|
243
288
|
# Convert to new format
|
244
289
|
new_config = ConfigConverter.to_security_framework_config(legacy_config)
|
245
|
-
|
290
|
+
|
246
291
|
# Add security section to legacy config
|
247
292
|
legacy_config["security"] = new_config
|
248
|
-
|
293
|
+
|
249
294
|
# Determine output path
|
250
295
|
if output_path is None:
|
251
|
-
output_path = config_path.replace(
|
252
|
-
|
296
|
+
output_path = config_path.replace(".json", "_migrated.json")
|
297
|
+
|
253
298
|
# Write migrated configuration
|
254
|
-
with open(output_path,
|
299
|
+
with open(output_path, "w", encoding="utf-8") as f:
|
255
300
|
json.dump(legacy_config, f, indent=2, ensure_ascii=False)
|
256
|
-
|
301
|
+
|
257
302
|
logger.info(f"Configuration migrated successfully to {output_path}")
|
258
303
|
return True
|
259
|
-
|
304
|
+
|
260
305
|
except Exception as e:
|
261
306
|
logger.error(f"Failed to migrate configuration: {e}")
|
262
307
|
return False
|
263
|
-
|
308
|
+
|
264
309
|
@staticmethod
|
265
310
|
def validate_security_config(config: Dict[str, Any]) -> bool:
|
266
311
|
"""
|
267
312
|
Validate security configuration format.
|
268
|
-
|
313
|
+
|
269
314
|
Args:
|
270
315
|
config: Configuration dictionary to validate
|
271
|
-
|
316
|
+
|
272
317
|
Returns:
|
273
318
|
True if configuration is valid, False otherwise
|
274
319
|
"""
|
@@ -277,64 +322,66 @@ class ConfigConverter:
|
|
277
322
|
if "security" not in config:
|
278
323
|
logger.error("Security section not found in configuration")
|
279
324
|
return False
|
280
|
-
|
325
|
+
|
281
326
|
security_section = config["security"]
|
282
|
-
|
327
|
+
|
283
328
|
# Validate required fields
|
284
329
|
required_sections = ["auth", "ssl", "permissions", "rate_limit"]
|
285
330
|
for section in required_sections:
|
286
331
|
if section not in security_section:
|
287
|
-
logger.error(
|
332
|
+
logger.error(
|
333
|
+
f"Required section '{section}' not found in security configuration"
|
334
|
+
)
|
288
335
|
return False
|
289
|
-
|
336
|
+
|
290
337
|
if not isinstance(security_section[section], dict):
|
291
338
|
logger.error(f"Section '{section}' must be a dictionary")
|
292
339
|
return False
|
293
|
-
|
340
|
+
|
294
341
|
# Validate auth configuration
|
295
342
|
auth_config = security_section["auth"]
|
296
343
|
if not isinstance(auth_config.get("methods", []), list):
|
297
344
|
logger.error("Auth methods must be a list")
|
298
345
|
return False
|
299
|
-
|
346
|
+
|
300
347
|
if not isinstance(auth_config.get("api_keys", {}), dict):
|
301
348
|
logger.error("API keys must be a dictionary")
|
302
349
|
return False
|
303
|
-
|
350
|
+
|
304
351
|
# Validate SSL configuration
|
305
352
|
ssl_config = security_section["ssl"]
|
306
353
|
if not isinstance(ssl_config.get("enabled", False), bool):
|
307
354
|
logger.error("SSL enabled must be a boolean")
|
308
355
|
return False
|
309
|
-
|
356
|
+
|
310
357
|
# Validate permissions configuration
|
311
358
|
permissions_config = security_section["permissions"]
|
312
359
|
if not isinstance(permissions_config.get("enabled", True), bool):
|
313
360
|
logger.error("Permissions enabled must be a boolean")
|
314
361
|
return False
|
315
|
-
|
362
|
+
|
316
363
|
# Validate rate limit configuration
|
317
364
|
rate_limit_config = security_section["rate_limit"]
|
318
365
|
if not isinstance(rate_limit_config.get("enabled", True), bool):
|
319
366
|
logger.error("Rate limit enabled must be a boolean")
|
320
367
|
return False
|
321
|
-
|
368
|
+
|
322
369
|
if not isinstance(rate_limit_config.get("requests_per_minute", 60), int):
|
323
370
|
logger.error("Requests per minute must be an integer")
|
324
371
|
return False
|
325
|
-
|
372
|
+
|
326
373
|
logger.info("Security configuration validation passed")
|
327
374
|
return True
|
328
|
-
|
375
|
+
|
329
376
|
except Exception as e:
|
330
377
|
logger.error(f"Configuration validation failed: {e}")
|
331
378
|
return False
|
332
|
-
|
379
|
+
|
333
380
|
@staticmethod
|
334
381
|
def _get_default_security_config() -> Dict[str, Any]:
|
335
382
|
"""
|
336
383
|
Get default security framework configuration.
|
337
|
-
|
384
|
+
|
338
385
|
Returns:
|
339
386
|
Default security framework configuration
|
340
387
|
"""
|
@@ -344,7 +391,7 @@ class ConfigConverter:
|
|
344
391
|
"methods": ["api_key"],
|
345
392
|
"api_keys": {},
|
346
393
|
"jwt_secret": "",
|
347
|
-
"jwt_algorithm": "HS256"
|
394
|
+
"jwt_algorithm": "HS256",
|
348
395
|
},
|
349
396
|
"ssl": {
|
350
397
|
"enabled": False,
|
@@ -353,13 +400,13 @@ class ConfigConverter:
|
|
353
400
|
"ca_cert": None,
|
354
401
|
"min_tls_version": "TLSv1.2",
|
355
402
|
"verify_client": False,
|
356
|
-
"client_cert_required": False
|
403
|
+
"client_cert_required": False,
|
357
404
|
},
|
358
405
|
"permissions": {
|
359
406
|
"enabled": True,
|
360
407
|
"roles_file": "roles.json",
|
361
408
|
"default_role": "user",
|
362
|
-
"deny_by_default": True
|
409
|
+
"deny_by_default": True,
|
363
410
|
},
|
364
411
|
"rate_limit": {
|
365
412
|
"enabled": True,
|
@@ -367,15 +414,15 @@ class ConfigConverter:
|
|
367
414
|
"requests_per_hour": 1000,
|
368
415
|
"burst_limit": 10,
|
369
416
|
"by_ip": True,
|
370
|
-
"by_user": True
|
371
|
-
}
|
417
|
+
"by_user": True,
|
418
|
+
},
|
372
419
|
}
|
373
|
-
|
420
|
+
|
374
421
|
@staticmethod
|
375
422
|
def _get_default_mcp_config() -> Dict[str, Any]:
|
376
423
|
"""
|
377
424
|
Get default mcp_proxy_adapter configuration.
|
378
|
-
|
425
|
+
|
379
426
|
Returns:
|
380
427
|
Default mcp_proxy_adapter configuration
|
381
428
|
"""
|
@@ -383,23 +430,9 @@ class ConfigConverter:
|
|
383
430
|
"security": {
|
384
431
|
"framework": "mcp_security_framework",
|
385
432
|
"enabled": True,
|
386
|
-
"auth": {
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
},
|
391
|
-
"ssl": {
|
392
|
-
"enabled": False,
|
393
|
-
"cert_file": None,
|
394
|
-
"key_file": None
|
395
|
-
},
|
396
|
-
"permissions": {
|
397
|
-
"enabled": True,
|
398
|
-
"roles_file": "roles.json"
|
399
|
-
},
|
400
|
-
"rate_limit": {
|
401
|
-
"enabled": True,
|
402
|
-
"requests_per_minute": 60
|
403
|
-
}
|
433
|
+
"auth": {"enabled": True, "methods": ["api_key"], "api_keys": {}},
|
434
|
+
"ssl": {"enabled": False, "cert_file": None, "key_file": None},
|
435
|
+
"permissions": {"enabled": True, "roles_file": "roles.json"},
|
436
|
+
"rate_limit": {"enabled": True, "requests_per_minute": 60},
|
404
437
|
}
|
405
438
|
}
|
@@ -173,7 +173,9 @@ class ConfigValidator:
|
|
173
173
|
if auth_config.get("enabled", False):
|
174
174
|
api_keys = auth_config.get("api_keys", {})
|
175
175
|
if not api_keys:
|
176
|
-
self.errors.append(
|
176
|
+
self.errors.append(
|
177
|
+
"API keys are required when authentication is enabled"
|
178
|
+
)
|
177
179
|
return False
|
178
180
|
|
179
181
|
# Validate API key format
|
@@ -192,7 +194,9 @@ class ConfigValidator:
|
|
192
194
|
if commands_config.get("auto_discovery", True):
|
193
195
|
commands_dir = commands_config.get("commands_directory", "./commands")
|
194
196
|
if not os.path.exists(commands_dir):
|
195
|
-
self.warnings.append(
|
197
|
+
self.warnings.append(
|
198
|
+
f"Commands directory does not exist: {commands_dir}"
|
199
|
+
)
|
196
200
|
|
197
201
|
return True
|
198
202
|
|
@@ -207,7 +211,9 @@ class ConfigValidator:
|
|
207
211
|
key_file = ssl_config.get("key_file")
|
208
212
|
|
209
213
|
if not cert_file or not key_file:
|
210
|
-
self.errors.append(
|
214
|
+
self.errors.append(
|
215
|
+
"SSL certificate and key files are required when SSL is enabled"
|
216
|
+
)
|
211
217
|
return False
|
212
218
|
|
213
219
|
if not os.path.exists(cert_file):
|
@@ -226,7 +232,9 @@ class ConfigValidator:
|
|
226
232
|
if roles_enabled:
|
227
233
|
config_file = roles_config.get("config_file")
|
228
234
|
if not config_file:
|
229
|
-
self.errors.append(
|
235
|
+
self.errors.append(
|
236
|
+
"Roles config file is required when roles are enabled"
|
237
|
+
)
|
230
238
|
return False
|
231
239
|
|
232
240
|
if not os.path.exists(config_file):
|