mcp-proxy-adapter 6.9.16__py3-none-any.whl โ 6.9.18__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/api/app.py +57 -55
- mcp_proxy_adapter/api/handlers.py +5 -5
- mcp_proxy_adapter/api/middleware/__init__.py +8 -8
- mcp_proxy_adapter/api/middleware/base.py +14 -14
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +7 -7
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -9
- mcp_proxy_adapter/api/middleware/factory.py +17 -17
- mcp_proxy_adapter/api/middleware/logging.py +6 -6
- mcp_proxy_adapter/api/middleware/performance.py +3 -3
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +19 -19
- mcp_proxy_adapter/api/middleware/transport_middleware.py +3 -3
- mcp_proxy_adapter/api/middleware/unified_security.py +11 -11
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +21 -21
- mcp_proxy_adapter/api/tool_integration.py +3 -2
- mcp_proxy_adapter/api/tools.py +4 -3
- mcp_proxy_adapter/commands/auth_validation_command.py +6 -5
- mcp_proxy_adapter/commands/base.py +10 -10
- mcp_proxy_adapter/commands/builtin_commands.py +6 -6
- mcp_proxy_adapter/commands/catalog_manager.py +74 -74
- mcp_proxy_adapter/commands/cert_monitor_command.py +13 -12
- mcp_proxy_adapter/commands/certificate_management_command.py +20 -19
- mcp_proxy_adapter/commands/command_registry.py +88 -80
- mcp_proxy_adapter/commands/config_command.py +3 -1
- mcp_proxy_adapter/commands/dependency_manager.py +10 -10
- mcp_proxy_adapter/commands/help_command.py +21 -20
- mcp_proxy_adapter/commands/hooks.py +27 -27
- mcp_proxy_adapter/commands/key_management_command.py +19 -18
- mcp_proxy_adapter/commands/plugins_command.py +2 -1
- mcp_proxy_adapter/commands/protocol_management_command.py +6 -6
- mcp_proxy_adapter/commands/proxy_registration_command.py +9 -9
- mcp_proxy_adapter/commands/registration_status_command.py +4 -4
- mcp_proxy_adapter/commands/reload_command.py +5 -5
- mcp_proxy_adapter/commands/role_test_command.py +2 -1
- mcp_proxy_adapter/commands/roles_management_command.py +9 -8
- mcp_proxy_adapter/commands/security_command.py +3 -2
- mcp_proxy_adapter/commands/ssl_setup_command.py +7 -6
- mcp_proxy_adapter/commands/token_management_command.py +12 -11
- mcp_proxy_adapter/commands/transport_management_command.py +2 -2
- mcp_proxy_adapter/config.py +3 -3
- mcp_proxy_adapter/core/__init__.py +1 -1
- mcp_proxy_adapter/core/app_factory.py +1 -1
- mcp_proxy_adapter/core/app_runner.py +3 -3
- mcp_proxy_adapter/core/auth_validator.py +9 -9
- mcp_proxy_adapter/core/certificate_utils.py +27 -27
- mcp_proxy_adapter/core/client_manager.py +13 -13
- mcp_proxy_adapter/core/client_security.py +26 -26
- mcp_proxy_adapter/core/config_converter.py +18 -18
- mcp_proxy_adapter/core/config_validator.py +5 -1
- mcp_proxy_adapter/core/crl_utils.py +22 -22
- mcp_proxy_adapter/core/logging.py +21 -13
- mcp_proxy_adapter/core/mtls_asgi.py +7 -7
- mcp_proxy_adapter/core/mtls_asgi_app.py +9 -9
- mcp_proxy_adapter/core/mtls_proxy.py +9 -9
- mcp_proxy_adapter/core/mtls_server.py +18 -18
- mcp_proxy_adapter/core/protocol_manager.py +29 -29
- mcp_proxy_adapter/core/proxy_registration.py +67 -67
- mcp_proxy_adapter/core/security_adapter.py +18 -18
- mcp_proxy_adapter/core/security_factory.py +16 -16
- mcp_proxy_adapter/core/security_integration.py +6 -6
- mcp_proxy_adapter/core/server_adapter.py +12 -12
- mcp_proxy_adapter/core/server_engine.py +17 -17
- mcp_proxy_adapter/core/signal_handler.py +12 -12
- mcp_proxy_adapter/core/ssl_utils.py +12 -12
- mcp_proxy_adapter/core/transport_manager.py +14 -14
- mcp_proxy_adapter/core/unified_config_adapter.py +6 -6
- mcp_proxy_adapter/core/utils.py +5 -5
- mcp_proxy_adapter/custom_openapi.py +7 -7
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +2 -2
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +6 -5
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +44 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +66 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +64 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +21 -21
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +6 -6
- mcp_proxy_adapter/examples/full_application/main.py +28 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +38 -38
- mcp_proxy_adapter/examples/run_proxy_server.py +20 -10
- mcp_proxy_adapter/examples/test_framework_complete.py +35 -35
- mcp_proxy_adapter/examples/test_mcp_server.py +2 -2
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +386 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +248 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.16.dist-info โ mcp_proxy_adapter-6.9.18.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.9.18.dist-info/RECORD +149 -0
- mcp_proxy_adapter-6.9.16.dist-info/RECORD +0 -144
- {mcp_proxy_adapter-6.9.16.dist-info โ mcp_proxy_adapter-6.9.18.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.16.dist-info โ mcp_proxy_adapter-6.9.18.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.9.16.dist-info โ mcp_proxy_adapter-6.9.18.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,386 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Script to validate compatibility between config generator and validator.
|
4
|
+
|
5
|
+
Author: Vasiliy Zdanovskiy
|
6
|
+
email: vasilyvz@gmail.com
|
7
|
+
"""
|
8
|
+
|
9
|
+
import json
|
10
|
+
import sys
|
11
|
+
import tempfile
|
12
|
+
import shutil
|
13
|
+
from pathlib import Path
|
14
|
+
from typing import Dict, Any, List
|
15
|
+
|
16
|
+
# Add the project root to the path
|
17
|
+
project_root = Path(__file__).parent.parent.parent
|
18
|
+
sys.path.insert(0, str(project_root))
|
19
|
+
|
20
|
+
from mcp_proxy_adapter.core.config_validator import ConfigValidator
|
21
|
+
from mcp_proxy_adapter.examples.config_builder import generate_complete_config
|
22
|
+
|
23
|
+
|
24
|
+
def test_generator_validator_compatibility():
|
25
|
+
"""Test that generated configs pass validation."""
|
26
|
+
print("๐ Testing Generator-Validator Compatibility")
|
27
|
+
print("=" * 50)
|
28
|
+
|
29
|
+
# Test configurations to generate
|
30
|
+
test_configs = [
|
31
|
+
{
|
32
|
+
"name": "HTTP Basic",
|
33
|
+
"protocol": "http",
|
34
|
+
"ssl_enabled": False,
|
35
|
+
"security_enabled": False,
|
36
|
+
"roles_enabled": False,
|
37
|
+
"proxy_registration_enabled": False
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"name": "HTTP + Token",
|
41
|
+
"protocol": "http",
|
42
|
+
"ssl_enabled": False,
|
43
|
+
"security_enabled": True,
|
44
|
+
"roles_enabled": False,
|
45
|
+
"proxy_registration_enabled": False
|
46
|
+
},
|
47
|
+
{
|
48
|
+
"name": "HTTP + Token + Roles",
|
49
|
+
"protocol": "http",
|
50
|
+
"ssl_enabled": False,
|
51
|
+
"security_enabled": True,
|
52
|
+
"roles_enabled": True,
|
53
|
+
"proxy_registration_enabled": False
|
54
|
+
},
|
55
|
+
{
|
56
|
+
"name": "HTTPS Basic",
|
57
|
+
"protocol": "https",
|
58
|
+
"ssl_enabled": True,
|
59
|
+
"security_enabled": False,
|
60
|
+
"roles_enabled": False,
|
61
|
+
"proxy_registration_enabled": False
|
62
|
+
},
|
63
|
+
{
|
64
|
+
"name": "HTTPS + Token",
|
65
|
+
"protocol": "https",
|
66
|
+
"ssl_enabled": True,
|
67
|
+
"security_enabled": True,
|
68
|
+
"roles_enabled": False,
|
69
|
+
"proxy_registration_enabled": False
|
70
|
+
},
|
71
|
+
{
|
72
|
+
"name": "HTTPS + Token + Roles",
|
73
|
+
"protocol": "https",
|
74
|
+
"ssl_enabled": True,
|
75
|
+
"security_enabled": True,
|
76
|
+
"roles_enabled": True,
|
77
|
+
"proxy_registration_enabled": False
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"name": "mTLS + Proxy Registration",
|
81
|
+
"protocol": "mtls",
|
82
|
+
"ssl_enabled": True,
|
83
|
+
"security_enabled": False,
|
84
|
+
"roles_enabled": False,
|
85
|
+
"proxy_registration_enabled": True
|
86
|
+
}
|
87
|
+
]
|
88
|
+
|
89
|
+
results = []
|
90
|
+
|
91
|
+
for test_config in test_configs:
|
92
|
+
print(f"\n๐ Testing: {test_config['name']}")
|
93
|
+
print("-" * 30)
|
94
|
+
|
95
|
+
try:
|
96
|
+
# Generate configuration
|
97
|
+
print(" ๐ง Generating configuration...")
|
98
|
+
generated_config = generate_complete_config(
|
99
|
+
host="localhost",
|
100
|
+
port=8080
|
101
|
+
)
|
102
|
+
|
103
|
+
# Create temporary test files
|
104
|
+
temp_dir = Path(tempfile.mkdtemp())
|
105
|
+
test_files = {}
|
106
|
+
|
107
|
+
# Modify config based on test parameters
|
108
|
+
if test_config["protocol"] != "http":
|
109
|
+
generated_config["server"]["protocol"] = test_config["protocol"]
|
110
|
+
|
111
|
+
if test_config["ssl_enabled"]:
|
112
|
+
generated_config["ssl"]["enabled"] = True
|
113
|
+
# Create test SSL certificates
|
114
|
+
cert_file = temp_dir / "test_cert.crt"
|
115
|
+
key_file = temp_dir / "test_key.key"
|
116
|
+
ca_cert = temp_dir / "test_ca.crt"
|
117
|
+
|
118
|
+
# Create dummy certificate files
|
119
|
+
cert_file.write_text("-----BEGIN CERTIFICATE-----\nDUMMY CERT\n-----END CERTIFICATE-----")
|
120
|
+
key_file.write_text("-----BEGIN PRIVATE KEY-----\nDUMMY KEY\n-----END PRIVATE KEY-----")
|
121
|
+
ca_cert.write_text("-----BEGIN CERTIFICATE-----\nDUMMY CA\n-----END CERTIFICATE-----")
|
122
|
+
|
123
|
+
generated_config["ssl"]["cert_file"] = str(cert_file)
|
124
|
+
generated_config["ssl"]["key_file"] = str(key_file)
|
125
|
+
generated_config["ssl"]["ca_cert"] = str(ca_cert)
|
126
|
+
|
127
|
+
test_files["ssl"] = [cert_file, key_file, ca_cert]
|
128
|
+
|
129
|
+
if test_config["security_enabled"]:
|
130
|
+
generated_config["security"]["enabled"] = True
|
131
|
+
generated_config["security"]["tokens"] = {
|
132
|
+
"test_token": {"permissions": ["*"]}
|
133
|
+
}
|
134
|
+
|
135
|
+
if test_config["roles_enabled"]:
|
136
|
+
generated_config["roles"]["enabled"] = True
|
137
|
+
roles_file = temp_dir / "test_roles.json"
|
138
|
+
roles_file.write_text('{"admin": ["*"], "user": ["read"]}')
|
139
|
+
generated_config["roles"]["config_file"] = str(roles_file)
|
140
|
+
test_files["roles"] = [roles_file]
|
141
|
+
|
142
|
+
if test_config["proxy_registration_enabled"]:
|
143
|
+
generated_config["proxy_registration"]["enabled"] = True
|
144
|
+
generated_config["proxy_registration"]["proxy_url"] = "http://localhost:3005"
|
145
|
+
|
146
|
+
# Create test client certificates
|
147
|
+
client_cert = temp_dir / "test_client.crt"
|
148
|
+
client_key = temp_dir / "test_client.key"
|
149
|
+
client_cert.write_text("-----BEGIN CERTIFICATE-----\nDUMMY CLIENT CERT\n-----END CERTIFICATE-----")
|
150
|
+
client_key.write_text("-----BEGIN PRIVATE KEY-----\nDUMMY CLIENT KEY\n-----END PRIVATE KEY-----")
|
151
|
+
|
152
|
+
generated_config["proxy_registration"]["certificate"] = {
|
153
|
+
"cert_file": str(client_cert),
|
154
|
+
"key_file": str(client_key)
|
155
|
+
}
|
156
|
+
generated_config["proxy_registration"]["ssl"] = {
|
157
|
+
"ca_cert": str(ca_cert) if test_config["ssl_enabled"] else str(temp_dir / "test_ca.crt")
|
158
|
+
}
|
159
|
+
|
160
|
+
if "proxy" not in test_files:
|
161
|
+
test_files["proxy"] = []
|
162
|
+
test_files["proxy"].extend([client_cert, client_key])
|
163
|
+
|
164
|
+
# Validate configuration
|
165
|
+
print(" โ
Validating configuration...")
|
166
|
+
validator = ConfigValidator()
|
167
|
+
validator.config_data = generated_config
|
168
|
+
validation_results = validator.validate_config()
|
169
|
+
|
170
|
+
# Analyze results
|
171
|
+
errors = [r for r in validation_results if r.level == "error"]
|
172
|
+
warnings = [r for r in validation_results if r.level == "warning"]
|
173
|
+
info = [r for r in validation_results if r.level == "info"]
|
174
|
+
|
175
|
+
result = {
|
176
|
+
"name": test_config["name"],
|
177
|
+
"success": len(errors) == 0,
|
178
|
+
"errors": len(errors),
|
179
|
+
"warnings": len(warnings),
|
180
|
+
"info": len(info),
|
181
|
+
"error_details": errors,
|
182
|
+
"warning_details": warnings
|
183
|
+
}
|
184
|
+
|
185
|
+
results.append(result)
|
186
|
+
|
187
|
+
# Clean up temporary files
|
188
|
+
try:
|
189
|
+
shutil.rmtree(temp_dir)
|
190
|
+
except Exception as e:
|
191
|
+
print(f" โ ๏ธ Warning: Could not clean up temp files: {e}")
|
192
|
+
|
193
|
+
# Print results
|
194
|
+
if result["success"]:
|
195
|
+
print(f" โ
PASS - {len(warnings)} warnings, {len(info)} info")
|
196
|
+
else:
|
197
|
+
print(f" โ FAIL - {len(errors)} errors, {len(warnings)} warnings")
|
198
|
+
for error in errors[:3]: # Show first 3 errors
|
199
|
+
print(f" โข {error.message}")
|
200
|
+
if len(errors) > 3:
|
201
|
+
print(f" ... and {len(errors) - 3} more errors")
|
202
|
+
|
203
|
+
except Exception as e:
|
204
|
+
print(f" ๐ฅ EXCEPTION: {str(e)}")
|
205
|
+
results.append({
|
206
|
+
"name": test_config["name"],
|
207
|
+
"success": False,
|
208
|
+
"errors": 1,
|
209
|
+
"warnings": 0,
|
210
|
+
"info": 0,
|
211
|
+
"error_details": [f"Exception: {str(e)}"],
|
212
|
+
"warning_details": []
|
213
|
+
})
|
214
|
+
|
215
|
+
# Summary
|
216
|
+
print("\n" + "=" * 50)
|
217
|
+
print("๐ COMPATIBILITY SUMMARY")
|
218
|
+
print("=" * 50)
|
219
|
+
|
220
|
+
total_tests = len(results)
|
221
|
+
passed_tests = sum(1 for r in results if r["success"])
|
222
|
+
failed_tests = total_tests - passed_tests
|
223
|
+
|
224
|
+
print(f"Total tests: {total_tests}")
|
225
|
+
print(f"Passed: {passed_tests}")
|
226
|
+
print(f"Failed: {failed_tests}")
|
227
|
+
print(f"Success rate: {(passed_tests/total_tests)*100:.1f}%")
|
228
|
+
|
229
|
+
if failed_tests > 0:
|
230
|
+
print("\nโ FAILED TESTS:")
|
231
|
+
for result in results:
|
232
|
+
if not result["success"]:
|
233
|
+
print(f" โข {result['name']}: {result['errors']} errors")
|
234
|
+
for error in result["error_details"][:2]:
|
235
|
+
print(f" - {error}")
|
236
|
+
|
237
|
+
return results
|
238
|
+
|
239
|
+
|
240
|
+
def test_validation_coverage():
|
241
|
+
"""Test that validator covers all generator features."""
|
242
|
+
print("\n๐ Testing Validation Coverage")
|
243
|
+
print("=" * 50)
|
244
|
+
|
245
|
+
# Test that validator checks all required sections
|
246
|
+
required_sections = [
|
247
|
+
"server", "logging", "commands", "debug"
|
248
|
+
]
|
249
|
+
|
250
|
+
optional_sections = [
|
251
|
+
"ssl", "security", "roles", "proxy_registration", "transport"
|
252
|
+
]
|
253
|
+
|
254
|
+
print("๐ Required sections validation:")
|
255
|
+
for section in required_sections:
|
256
|
+
print(f" โ
{section}")
|
257
|
+
|
258
|
+
print("\n๐ Optional sections validation:")
|
259
|
+
for section in optional_sections:
|
260
|
+
print(f" โ
{section}")
|
261
|
+
|
262
|
+
return True
|
263
|
+
|
264
|
+
|
265
|
+
def test_edge_cases():
|
266
|
+
"""Test edge cases and error conditions."""
|
267
|
+
print("\n๐ Testing Edge Cases")
|
268
|
+
print("=" * 50)
|
269
|
+
|
270
|
+
edge_cases = [
|
271
|
+
{
|
272
|
+
"name": "Empty config",
|
273
|
+
"config": {},
|
274
|
+
"should_fail": True
|
275
|
+
},
|
276
|
+
{
|
277
|
+
"name": "Missing server section",
|
278
|
+
"config": {"logging": {"level": "INFO"}},
|
279
|
+
"should_fail": True
|
280
|
+
},
|
281
|
+
{
|
282
|
+
"name": "Invalid protocol",
|
283
|
+
"config": {
|
284
|
+
"server": {"protocol": "invalid", "host": "localhost", "port": 8080},
|
285
|
+
"logging": {"level": "INFO"},
|
286
|
+
"commands": {"enabled": True},
|
287
|
+
"debug": {"enabled": False}
|
288
|
+
},
|
289
|
+
"should_fail": True
|
290
|
+
},
|
291
|
+
{
|
292
|
+
"name": "SSL enabled without certificates",
|
293
|
+
"config": {
|
294
|
+
"server": {"protocol": "https", "host": "localhost", "port": 8080},
|
295
|
+
"ssl": {"enabled": True},
|
296
|
+
"logging": {"level": "INFO"},
|
297
|
+
"commands": {"enabled": True},
|
298
|
+
"debug": {"enabled": False}
|
299
|
+
},
|
300
|
+
"should_fail": True
|
301
|
+
}
|
302
|
+
]
|
303
|
+
|
304
|
+
results = []
|
305
|
+
|
306
|
+
for case in edge_cases:
|
307
|
+
print(f"\n๐งช Testing: {case['name']}")
|
308
|
+
|
309
|
+
try:
|
310
|
+
validator = ConfigValidator()
|
311
|
+
validator.config_data = case["config"]
|
312
|
+
validation_results = validator.validate_config()
|
313
|
+
|
314
|
+
errors = [r for r in validation_results if r.level == "error"]
|
315
|
+
has_errors = len(errors) > 0
|
316
|
+
|
317
|
+
expected_failure = case["should_fail"]
|
318
|
+
test_passed = (has_errors == expected_failure)
|
319
|
+
|
320
|
+
if test_passed:
|
321
|
+
print(f" โ
PASS - {'Correctly failed' if has_errors else 'Correctly passed'}")
|
322
|
+
else:
|
323
|
+
print(f" โ FAIL - Expected {'failure' if expected_failure else 'success'}, got {'failure' if has_errors else 'success'}")
|
324
|
+
|
325
|
+
results.append({
|
326
|
+
"name": case["name"],
|
327
|
+
"passed": test_passed,
|
328
|
+
"errors": len(errors)
|
329
|
+
})
|
330
|
+
|
331
|
+
except Exception as e:
|
332
|
+
print(f" ๐ฅ EXCEPTION: {str(e)}")
|
333
|
+
results.append({
|
334
|
+
"name": case["name"],
|
335
|
+
"passed": False,
|
336
|
+
"errors": 1
|
337
|
+
})
|
338
|
+
|
339
|
+
return results
|
340
|
+
|
341
|
+
|
342
|
+
def main():
|
343
|
+
"""Main test function."""
|
344
|
+
print("๐ Generator-Validator Compatibility Test")
|
345
|
+
print("=" * 60)
|
346
|
+
|
347
|
+
try:
|
348
|
+
# Test 1: Generator-Validator compatibility
|
349
|
+
compatibility_results = test_generator_validator_compatibility()
|
350
|
+
|
351
|
+
# Test 2: Validation coverage
|
352
|
+
test_validation_coverage()
|
353
|
+
|
354
|
+
# Test 3: Edge cases
|
355
|
+
edge_case_results = test_edge_cases()
|
356
|
+
|
357
|
+
# Final summary
|
358
|
+
print("\n" + "=" * 60)
|
359
|
+
print("๐ฏ FINAL RESULTS")
|
360
|
+
print("=" * 60)
|
361
|
+
|
362
|
+
compatibility_passed = sum(1 for r in compatibility_results if r["success"])
|
363
|
+
edge_cases_passed = sum(1 for r in edge_case_results if r["passed"])
|
364
|
+
|
365
|
+
print(f"Compatibility tests: {compatibility_passed}/{len(compatibility_results)} passed")
|
366
|
+
print(f"Edge case tests: {edge_cases_passed}/{len(edge_case_results)} passed")
|
367
|
+
|
368
|
+
total_passed = compatibility_passed + edge_cases_passed
|
369
|
+
total_tests = len(compatibility_results) + len(edge_case_results)
|
370
|
+
|
371
|
+
print(f"Overall: {total_passed}/{total_tests} tests passed")
|
372
|
+
|
373
|
+
if total_passed == total_tests:
|
374
|
+
print("๐ ALL TESTS PASSED! Generator and validator are compatible.")
|
375
|
+
return 0
|
376
|
+
else:
|
377
|
+
print("โ Some tests failed. Check the output above for details.")
|
378
|
+
return 1
|
379
|
+
|
380
|
+
except Exception as e:
|
381
|
+
print(f"๐ฅ Test suite failed with exception: {str(e)}")
|
382
|
+
return 1
|
383
|
+
|
384
|
+
|
385
|
+
if __name__ == "__main__":
|
386
|
+
sys.exit(main())
|
@@ -0,0 +1,248 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Simple compatibility test between config generator and validator.
|
4
|
+
Tests only the structure and required fields, not file existence or certificate validity.
|
5
|
+
|
6
|
+
Author: Vasiliy Zdanovskiy
|
7
|
+
email: vasilyvz@gmail.com
|
8
|
+
"""
|
9
|
+
|
10
|
+
import json
|
11
|
+
import sys
|
12
|
+
from pathlib import Path
|
13
|
+
from typing import Dict, Any, List
|
14
|
+
|
15
|
+
# Add the project root to the path
|
16
|
+
project_root = Path(__file__).parent.parent.parent
|
17
|
+
sys.path.insert(0, str(project_root))
|
18
|
+
|
19
|
+
from mcp_proxy_adapter.core.config_validator import ConfigValidator
|
20
|
+
from mcp_proxy_adapter.examples.config_builder import generate_complete_config
|
21
|
+
|
22
|
+
|
23
|
+
def test_generator_validator_structure():
|
24
|
+
"""Test that generated configs have the correct structure."""
|
25
|
+
print("๐ Testing Generator-Validator Structure Compatibility")
|
26
|
+
print("=" * 60)
|
27
|
+
|
28
|
+
# Test basic HTTP configuration
|
29
|
+
print("\n๐ Testing: HTTP Basic Configuration")
|
30
|
+
print("-" * 40)
|
31
|
+
|
32
|
+
try:
|
33
|
+
# Generate configuration
|
34
|
+
print(" ๐ง Generating configuration...")
|
35
|
+
config = generate_complete_config(host="localhost", port=8080)
|
36
|
+
|
37
|
+
# Check required sections exist
|
38
|
+
required_sections = ["server", "logging", "commands", "debug", "ssl", "security", "roles", "proxy_registration"]
|
39
|
+
missing_sections = []
|
40
|
+
|
41
|
+
for section in required_sections:
|
42
|
+
if section not in config:
|
43
|
+
missing_sections.append(section)
|
44
|
+
|
45
|
+
if missing_sections:
|
46
|
+
print(f" โ FAIL - Missing sections: {missing_sections}")
|
47
|
+
return False
|
48
|
+
|
49
|
+
# Check server section
|
50
|
+
server_required = ["host", "port", "protocol", "debug", "log_level"]
|
51
|
+
server_missing = [key for key in server_required if key not in config["server"]]
|
52
|
+
|
53
|
+
if server_missing:
|
54
|
+
print(f" โ FAIL - Server section missing keys: {server_missing}")
|
55
|
+
return False
|
56
|
+
|
57
|
+
# Check protocol is HTTP
|
58
|
+
if config["server"]["protocol"] != "http":
|
59
|
+
print(f" โ FAIL - Expected protocol 'http', got '{config['server']['protocol']}'")
|
60
|
+
return False
|
61
|
+
|
62
|
+
# Check SSL is disabled
|
63
|
+
if config["ssl"]["enabled"] != False:
|
64
|
+
print(f" โ FAIL - Expected SSL disabled, got {config['ssl']['enabled']}")
|
65
|
+
return False
|
66
|
+
|
67
|
+
# Check security is disabled
|
68
|
+
if config["security"]["enabled"] != False:
|
69
|
+
print(f" โ FAIL - Expected security disabled, got {config['security']['enabled']}")
|
70
|
+
return False
|
71
|
+
|
72
|
+
# Check roles is disabled
|
73
|
+
if config["roles"]["enabled"] != False:
|
74
|
+
print(f" โ FAIL - Expected roles disabled, got {config['roles']['enabled']}")
|
75
|
+
return False
|
76
|
+
|
77
|
+
# Check proxy registration is disabled
|
78
|
+
if config["proxy_registration"]["enabled"] != False:
|
79
|
+
print(f" โ FAIL - Expected proxy registration disabled, got {config['proxy_registration']['enabled']}")
|
80
|
+
return False
|
81
|
+
|
82
|
+
print(" โ
PASS - All required sections and fields present")
|
83
|
+
print(" โ
PASS - All features correctly disabled")
|
84
|
+
print(" โ
PASS - Protocol correctly set to HTTP")
|
85
|
+
|
86
|
+
return True
|
87
|
+
|
88
|
+
except Exception as e:
|
89
|
+
print(f" ๐ฅ EXCEPTION: {str(e)}")
|
90
|
+
return False
|
91
|
+
|
92
|
+
|
93
|
+
def test_config_modification():
|
94
|
+
"""Test that we can modify generated configs for different scenarios."""
|
95
|
+
print("\n๐ Testing: Configuration Modification")
|
96
|
+
print("-" * 40)
|
97
|
+
|
98
|
+
try:
|
99
|
+
# Generate base config
|
100
|
+
config = generate_complete_config(host="localhost", port=8080)
|
101
|
+
|
102
|
+
# Test 1: Enable HTTPS
|
103
|
+
print(" ๐ง Testing HTTPS modification...")
|
104
|
+
config["server"]["protocol"] = "https"
|
105
|
+
config["ssl"]["enabled"] = True
|
106
|
+
|
107
|
+
if config["server"]["protocol"] != "https":
|
108
|
+
print(" โ FAIL - Could not change protocol to HTTPS")
|
109
|
+
return False
|
110
|
+
|
111
|
+
if config["ssl"]["enabled"] != True:
|
112
|
+
print(" โ FAIL - Could not enable SSL")
|
113
|
+
return False
|
114
|
+
|
115
|
+
print(" โ
PASS - HTTPS modification successful")
|
116
|
+
|
117
|
+
# Test 2: Enable security
|
118
|
+
print(" ๐ง Testing security modification...")
|
119
|
+
config["security"]["enabled"] = True
|
120
|
+
config["security"]["tokens"] = {"test_token": {"permissions": ["*"]}}
|
121
|
+
|
122
|
+
if config["security"]["enabled"] != True:
|
123
|
+
print(" โ FAIL - Could not enable security")
|
124
|
+
return False
|
125
|
+
|
126
|
+
if "tokens" not in config["security"]:
|
127
|
+
print(" โ FAIL - Could not add tokens")
|
128
|
+
return False
|
129
|
+
|
130
|
+
print(" โ
PASS - Security modification successful")
|
131
|
+
|
132
|
+
# Test 3: Enable roles
|
133
|
+
print(" ๐ง Testing roles modification...")
|
134
|
+
config["roles"]["enabled"] = True
|
135
|
+
config["roles"]["config_file"] = "./test_roles.json"
|
136
|
+
|
137
|
+
if config["roles"]["enabled"] != True:
|
138
|
+
print(" โ FAIL - Could not enable roles")
|
139
|
+
return False
|
140
|
+
|
141
|
+
if config["roles"]["config_file"] != "./test_roles.json":
|
142
|
+
print(" โ FAIL - Could not set roles config file")
|
143
|
+
return False
|
144
|
+
|
145
|
+
print(" โ
PASS - Roles modification successful")
|
146
|
+
|
147
|
+
return True
|
148
|
+
|
149
|
+
except Exception as e:
|
150
|
+
print(f" ๐ฅ EXCEPTION: {str(e)}")
|
151
|
+
return False
|
152
|
+
|
153
|
+
|
154
|
+
def test_validator_accepts_generated_config():
|
155
|
+
"""Test that validator accepts the basic generated config without file checks."""
|
156
|
+
print("\n๐ Testing: Validator Accepts Generated Config")
|
157
|
+
print("-" * 40)
|
158
|
+
|
159
|
+
try:
|
160
|
+
# Generate config
|
161
|
+
config = generate_complete_config(host="localhost", port=8080)
|
162
|
+
|
163
|
+
# Create a mock validator that doesn't check files
|
164
|
+
class MockValidator(ConfigValidator):
|
165
|
+
def _validate_file_existence(self):
|
166
|
+
"""Skip file existence checks for testing."""
|
167
|
+
pass
|
168
|
+
|
169
|
+
def _validate_certificate_file(self, cert_file, section, key):
|
170
|
+
"""Skip certificate validation for testing."""
|
171
|
+
pass
|
172
|
+
|
173
|
+
def _validate_key_file(self, key_file, section, key):
|
174
|
+
"""Skip key validation for testing."""
|
175
|
+
pass
|
176
|
+
|
177
|
+
def _validate_ca_certificate_file(self, ca_cert_file, section, key):
|
178
|
+
"""Skip CA certificate validation for testing."""
|
179
|
+
pass
|
180
|
+
|
181
|
+
# Validate with mock validator
|
182
|
+
validator = MockValidator()
|
183
|
+
validator.config_data = config
|
184
|
+
results = validator.validate_config()
|
185
|
+
|
186
|
+
errors = [r for r in results if r.level == "error"]
|
187
|
+
warnings = [r for r in results if r.level == "warning"]
|
188
|
+
|
189
|
+
if len(errors) > 0:
|
190
|
+
print(f" โ FAIL - {len(errors)} validation errors:")
|
191
|
+
for error in errors[:3]:
|
192
|
+
print(f" โข {error.message}")
|
193
|
+
return False
|
194
|
+
|
195
|
+
print(f" โ
PASS - No validation errors ({len(warnings)} warnings)")
|
196
|
+
return True
|
197
|
+
|
198
|
+
except Exception as e:
|
199
|
+
print(f" ๐ฅ EXCEPTION: {str(e)}")
|
200
|
+
return False
|
201
|
+
|
202
|
+
|
203
|
+
def main():
|
204
|
+
"""Main test function."""
|
205
|
+
print("๐ Generator-Validator Structure Compatibility Test")
|
206
|
+
print("=" * 70)
|
207
|
+
|
208
|
+
tests = [
|
209
|
+
("Structure Test", test_generator_validator_structure),
|
210
|
+
("Modification Test", test_config_modification),
|
211
|
+
("Validator Acceptance Test", test_validator_accepts_generated_config)
|
212
|
+
]
|
213
|
+
|
214
|
+
results = []
|
215
|
+
|
216
|
+
for test_name, test_func in tests:
|
217
|
+
print(f"\n๐งช Running: {test_name}")
|
218
|
+
try:
|
219
|
+
result = test_func()
|
220
|
+
results.append((test_name, result))
|
221
|
+
except Exception as e:
|
222
|
+
print(f" ๐ฅ Test failed with exception: {str(e)}")
|
223
|
+
results.append((test_name, False))
|
224
|
+
|
225
|
+
# Summary
|
226
|
+
print("\n" + "=" * 70)
|
227
|
+
print("๐ฏ FINAL RESULTS")
|
228
|
+
print("=" * 70)
|
229
|
+
|
230
|
+
passed = sum(1 for _, result in results if result)
|
231
|
+
total = len(results)
|
232
|
+
|
233
|
+
print(f"Tests passed: {passed}/{total}")
|
234
|
+
|
235
|
+
for test_name, result in results:
|
236
|
+
status = "โ
PASS" if result else "โ FAIL"
|
237
|
+
print(f" {status} - {test_name}")
|
238
|
+
|
239
|
+
if passed == total:
|
240
|
+
print("\n๐ ALL TESTS PASSED! Generator and validator are structurally compatible.")
|
241
|
+
return 0
|
242
|
+
else:
|
243
|
+
print(f"\nโ {total - passed} tests failed. Check the output above for details.")
|
244
|
+
return 1
|
245
|
+
|
246
|
+
|
247
|
+
if __name__ == "__main__":
|
248
|
+
sys.exit(main())
|
mcp_proxy_adapter/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-proxy-adapter
|
3
|
-
Version: 6.9.
|
3
|
+
Version: 6.9.18
|
4
4
|
Summary: Powerful JSON-RPC microservices framework with built-in security, authentication, and proxy registration
|
5
5
|
Home-page: https://github.com/maverikod/mcp-proxy-adapter
|
6
6
|
Author: Vasiliy Zdanovskiy
|