mcp-proxy-adapter 6.4.36__py3-none-any.whl → 6.4.39__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/examples/create_test_configs.py +6 -31
- mcp_proxy_adapter/examples/run_full_test_suite.py +66 -52
- mcp_proxy_adapter/examples/run_security_tests.py +79 -24
- mcp_proxy_adapter/examples/security_test_client.py +17 -25
- mcp_proxy_adapter/examples/setup_test_environment.py +91 -98
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.4.36.dist-info → mcp_proxy_adapter-6.4.39.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.4.36.dist-info → mcp_proxy_adapter-6.4.39.dist-info}/RECORD +11 -11
- {mcp_proxy_adapter-6.4.36.dist-info → mcp_proxy_adapter-6.4.39.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.4.36.dist-info → mcp_proxy_adapter-6.4.39.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.4.36.dist-info → mcp_proxy_adapter-6.4.39.dist-info}/top_level.txt +0 -0
@@ -175,7 +175,8 @@ class TestConfigGenerator:
|
|
175
175
|
"security.auth.methods": ["certificate"],
|
176
176
|
"security.permissions.enabled": False,
|
177
177
|
"proxy_registration.enabled": False,
|
178
|
-
"protocols.allowed_protocols": ["https", "mtls"]
|
178
|
+
"protocols.allowed_protocols": ["https", "mtls"],
|
179
|
+
"protocols.default_protocol": "mtls"
|
179
180
|
})
|
180
181
|
|
181
182
|
# 7. mTLS with Proxy Registration
|
@@ -196,37 +197,11 @@ class TestConfigGenerator:
|
|
196
197
|
"protocols.allowed_protocols": ["https", "mtls"]
|
197
198
|
})
|
198
199
|
|
199
|
-
# 8. HTTP with Token Auth (for security tests)
|
200
|
-
|
201
|
-
"server.port": 8010,
|
202
|
-
"ssl.enabled": False,
|
203
|
-
"security.enabled": True,
|
204
|
-
"security.auth.enabled": True,
|
205
|
-
"security.auth.methods": ["api_key"],
|
206
|
-
"security.auth.api_keys": {
|
207
|
-
"admin": "admin-secret-key",
|
208
|
-
"user": "user-secret-key"
|
209
|
-
},
|
210
|
-
"proxy_registration.enabled": False,
|
211
|
-
"protocols.allowed_protocols": ["http"]
|
212
|
-
})
|
200
|
+
# 8. HTTP with Token Auth (for security tests) - REMOVED DUPLICATE
|
201
|
+
# This is already created above with correct port 20021
|
213
202
|
|
214
|
-
# 9. HTTPS with Token Auth (for security tests)
|
215
|
-
|
216
|
-
"server.port": 8011,
|
217
|
-
"ssl.enabled": True,
|
218
|
-
"ssl.cert_file": "certs/localhost_server.crt",
|
219
|
-
"ssl.key_file": "keys/localhost_server.key",
|
220
|
-
"security.enabled": True,
|
221
|
-
"security.auth.enabled": True,
|
222
|
-
"security.auth.methods": ["api_key"],
|
223
|
-
"security.auth.api_keys": {
|
224
|
-
"admin": "admin-secret-key",
|
225
|
-
"user": "user-secret-key"
|
226
|
-
},
|
227
|
-
"proxy_registration.enabled": False,
|
228
|
-
"protocols.allowed_protocols": ["https"]
|
229
|
-
})
|
203
|
+
# 9. HTTPS with Token Auth (for security tests) - REMOVED DUPLICATE
|
204
|
+
# This is already created above with correct port 20023
|
230
205
|
|
231
206
|
# 10. Full Featured (everything enabled)
|
232
207
|
self.create_config("full_featured", {
|
@@ -8,9 +8,7 @@ Automates the complete testing workflow.
|
|
8
8
|
import os
|
9
9
|
import sys
|
10
10
|
import subprocess
|
11
|
-
import time
|
12
11
|
from pathlib import Path
|
13
|
-
from typing import List, Dict, Optional
|
14
12
|
|
15
13
|
|
16
14
|
class FullTestSuiteRunner:
|
@@ -26,9 +24,9 @@ class FullTestSuiteRunner:
|
|
26
24
|
|
27
25
|
def print_step(self, step: str, description: str):
|
28
26
|
"""Print a formatted step header."""
|
29
|
-
print(f"\n{'='*60}")
|
27
|
+
print(f"\n{'=' * 60}")
|
30
28
|
print(f"🔧 STEP {step}: {description}")
|
31
|
-
print(f"{'='*60}")
|
29
|
+
print(f"{'=' * 60}")
|
32
30
|
|
33
31
|
def print_success(self, message: str):
|
34
32
|
"""Print a success message."""
|
@@ -114,8 +112,19 @@ class FullTestSuiteRunner:
|
|
114
112
|
self.print_step("3", "Certificate Generation")
|
115
113
|
|
116
114
|
try:
|
115
|
+
# Check if certificate generation script exists
|
116
|
+
cert_script = self.working_dir / "scripts" / "create_certificates_simple.py"
|
117
|
+
if not cert_script.exists():
|
118
|
+
# Try alternative path
|
119
|
+
cert_script = self.working_dir / "create_certificates_simple.py"
|
120
|
+
if not cert_script.exists():
|
121
|
+
self.print_error(
|
122
|
+
f"Certificate generation script not found: {cert_script}"
|
123
|
+
)
|
124
|
+
return False
|
125
|
+
|
117
126
|
# Run certificate generation script
|
118
|
-
cmd = [sys.executable,
|
127
|
+
cmd = [sys.executable, str(cert_script)]
|
119
128
|
self.print_info("Running certificate generation script...")
|
120
129
|
|
121
130
|
result = subprocess.run(
|
@@ -152,18 +161,29 @@ class FullTestSuiteRunner:
|
|
152
161
|
# Check if comprehensive_config.json exists
|
153
162
|
comprehensive_config = self.working_dir / "comprehensive_config.json"
|
154
163
|
if not comprehensive_config.exists():
|
155
|
-
self.print_error(
|
164
|
+
self.print_error(
|
165
|
+
f"Comprehensive config not found: {comprehensive_config}"
|
166
|
+
)
|
156
167
|
return False
|
157
168
|
|
158
|
-
self.print_info(
|
169
|
+
self.print_info(
|
170
|
+
"Generating test configurations from comprehensive config..."
|
171
|
+
)
|
159
172
|
self.print_info("This will create:")
|
160
173
|
self.print_info(" - HTTP configurations (simple and with auth)")
|
161
174
|
self.print_info(" - HTTPS configurations (simple and with auth)")
|
162
|
-
self.print_info(
|
175
|
+
self.print_info(
|
176
|
+
" - mTLS configurations (simple, with roles, with proxy registration)"
|
177
|
+
)
|
163
178
|
self.print_info(" - Full featured configuration (everything enabled)")
|
164
179
|
|
165
180
|
# Run the configuration generator
|
166
|
-
cmd = [
|
181
|
+
cmd = [
|
182
|
+
sys.executable,
|
183
|
+
"create_test_configs.py",
|
184
|
+
"--comprehensive-config",
|
185
|
+
"comprehensive_config.json",
|
186
|
+
]
|
167
187
|
result = subprocess.run(
|
168
188
|
cmd, capture_output=True, text=True, cwd=self.working_dir
|
169
189
|
)
|
@@ -173,36 +193,37 @@ class FullTestSuiteRunner:
|
|
173
193
|
if result.stdout:
|
174
194
|
print("Generator output:")
|
175
195
|
print(result.stdout)
|
176
|
-
|
196
|
+
|
177
197
|
# Create roles.json file
|
178
198
|
self.print_info("Creating roles.json file...")
|
179
199
|
roles_content = {
|
180
200
|
"roles": {
|
181
201
|
"admin": {
|
182
202
|
"permissions": ["*"],
|
183
|
-
"description": "Full administrative access"
|
203
|
+
"description": "Full administrative access",
|
184
204
|
},
|
185
205
|
"user": {
|
186
206
|
"permissions": ["read", "write"],
|
187
|
-
"description": "Standard user access"
|
207
|
+
"description": "Standard user access",
|
188
208
|
},
|
189
209
|
"readonly": {
|
190
210
|
"permissions": ["read"],
|
191
|
-
"description": "Read-only access"
|
211
|
+
"description": "Read-only access",
|
192
212
|
},
|
193
213
|
"guest": {
|
194
214
|
"permissions": ["read"],
|
195
|
-
"description": "Limited guest access"
|
196
|
-
}
|
215
|
+
"description": "Limited guest access",
|
216
|
+
},
|
197
217
|
}
|
198
218
|
}
|
199
|
-
|
219
|
+
|
200
220
|
roles_file = self.configs_dir / "roles.json"
|
201
221
|
import json
|
202
|
-
|
222
|
+
|
223
|
+
with open(roles_file, "w", encoding="utf-8") as f:
|
203
224
|
json.dump(roles_content, f, indent=2, ensure_ascii=False)
|
204
225
|
self.print_success(f"Created roles.json: {roles_file}")
|
205
|
-
|
226
|
+
|
206
227
|
return True
|
207
228
|
else:
|
208
229
|
self.print_error("Configuration generation failed!")
|
@@ -287,29 +308,28 @@ class FullTestSuiteRunner:
|
|
287
308
|
# Create test_proxy_registration.json config if it doesn't exist
|
288
309
|
test_config = self.configs_dir / "test_proxy_registration.json"
|
289
310
|
if not test_config.exists():
|
290
|
-
self.print_info(
|
311
|
+
self.print_info(
|
312
|
+
"Creating test_proxy_registration.json configuration..."
|
313
|
+
)
|
291
314
|
test_config_content = {
|
292
315
|
"uuid": "550e8400-e29b-41d4-a716-446655440001",
|
293
|
-
"server": {
|
294
|
-
"host": "127.0.0.1",
|
295
|
-
"port": 20005
|
296
|
-
},
|
316
|
+
"server": {"host": "127.0.0.1", "port": 20006},
|
297
317
|
"ssl": {
|
298
318
|
"enabled": True,
|
299
319
|
"cert_file": "certs/localhost_server.crt",
|
300
|
-
"key_file": "keys/
|
320
|
+
"key_file": "keys/server_key.pem",
|
301
321
|
"ca_cert": "certs/mcp_proxy_adapter_ca_ca.crt",
|
302
322
|
"client_cert_file": "certs/admin_cert.pem",
|
303
323
|
"client_key_file": "certs/admin_key.pem",
|
304
|
-
"verify_client": True
|
324
|
+
"verify_client": True,
|
305
325
|
},
|
306
326
|
"registration": {
|
307
327
|
"enabled": True,
|
308
328
|
"auth_method": "token",
|
309
|
-
"server_url": "
|
329
|
+
"server_url": "https://127.0.0.1:20005/proxy",
|
310
330
|
"token": {
|
311
331
|
"enabled": True,
|
312
|
-
"token": "proxy_registration_token_123"
|
332
|
+
"token": "proxy_registration_token_123",
|
313
333
|
},
|
314
334
|
"proxy_info": {
|
315
335
|
"name": "mcp_test_server",
|
@@ -317,50 +337,42 @@ class FullTestSuiteRunner:
|
|
317
337
|
"jsonrpc",
|
318
338
|
"rest",
|
319
339
|
"security",
|
320
|
-
"proxy_registration"
|
340
|
+
"proxy_registration",
|
321
341
|
],
|
322
342
|
"endpoints": {
|
323
343
|
"jsonrpc": "/api/jsonrpc",
|
324
344
|
"rest": "/cmd",
|
325
|
-
"health": "/health"
|
326
|
-
}
|
345
|
+
"health": "/health",
|
346
|
+
},
|
327
347
|
},
|
328
|
-
"heartbeat": {
|
329
|
-
"enabled": True,
|
330
|
-
"interval": 30
|
331
|
-
}
|
348
|
+
"heartbeat": {"enabled": True, "interval": 30},
|
332
349
|
},
|
333
350
|
"security": {
|
334
351
|
"enabled": True,
|
335
|
-
"auth": {
|
336
|
-
"enabled": True,
|
337
|
-
"methods": [
|
338
|
-
"certificate"
|
339
|
-
]
|
340
|
-
},
|
352
|
+
"auth": {"enabled": True, "methods": ["certificate"]},
|
341
353
|
"permissions": {
|
342
354
|
"enabled": True,
|
343
|
-
"roles_file": "configs/roles.json"
|
344
|
-
}
|
355
|
+
"roles_file": "configs/roles.json",
|
356
|
+
},
|
345
357
|
},
|
346
358
|
"protocols": {
|
347
359
|
"enabled": True,
|
348
360
|
"default_protocol": "mtls",
|
349
|
-
"allowed_protocols": [
|
350
|
-
|
351
|
-
"mtls"
|
352
|
-
]
|
353
|
-
}
|
361
|
+
"allowed_protocols": ["https", "mtls"],
|
362
|
+
},
|
354
363
|
}
|
355
|
-
|
364
|
+
|
356
365
|
import json
|
357
|
-
|
366
|
+
|
367
|
+
with open(test_config, "w", encoding="utf-8") as f:
|
358
368
|
json.dump(test_config_content, f, indent=2)
|
359
369
|
self.print_success(f"Created test configuration: {test_config}")
|
360
370
|
|
361
371
|
self.print_info("Running mTLS proxy registration test...")
|
362
372
|
self.print_info("This test verifies:")
|
363
|
-
self.print_info(
|
373
|
+
self.print_info(
|
374
|
+
" - mTLS server startup with client certificate verification"
|
375
|
+
)
|
364
376
|
self.print_info(" - Proxy registration functionality")
|
365
377
|
self.print_info(" - SSL configuration validation")
|
366
378
|
|
@@ -371,7 +383,9 @@ class FullTestSuiteRunner:
|
|
371
383
|
)
|
372
384
|
|
373
385
|
if result.returncode == 0:
|
374
|
-
self.print_success(
|
386
|
+
self.print_success(
|
387
|
+
"mTLS proxy registration test completed successfully!"
|
388
|
+
)
|
375
389
|
if result.stdout:
|
376
390
|
print("Test output:")
|
377
391
|
print(result.stdout)
|
@@ -461,7 +475,7 @@ class FullTestSuiteRunner:
|
|
461
475
|
return False
|
462
476
|
|
463
477
|
# All steps completed successfully
|
464
|
-
print(f"\n{'='*60}")
|
478
|
+
print(f"\n{'=' * 60}")
|
465
479
|
print("🎉 FULL TEST SUITE COMPLETED SUCCESSFULLY!")
|
466
480
|
print("=" * 60)
|
467
481
|
print("✅ Environment validated")
|
@@ -25,10 +25,19 @@ import psutil
|
|
25
25
|
import requests
|
26
26
|
|
27
27
|
# Import security test client with proper module path
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
try:
|
29
|
+
from mcp_proxy_adapter.examples.security_test_client import (
|
30
|
+
SecurityTestClient,
|
31
|
+
TestResult,
|
32
|
+
)
|
33
|
+
except ImportError:
|
34
|
+
# Fallback to local import if package import fails
|
35
|
+
current_dir = Path(__file__).parent
|
36
|
+
sys.path.insert(0, str(current_dir))
|
37
|
+
from security_test_client import (
|
38
|
+
SecurityTestClient,
|
39
|
+
TestResult,
|
40
|
+
)
|
32
41
|
|
33
42
|
|
34
43
|
class SecurityTestRunner:
|
@@ -49,31 +58,31 @@ class SecurityTestRunner:
|
|
49
58
|
"basic_http": {
|
50
59
|
"config": "configs/http_simple.json",
|
51
60
|
"port": 20020, # Dedicated port
|
52
|
-
"url":
|
61
|
+
"url": "http://127.0.0.1:20020",
|
53
62
|
"auth": "none",
|
54
63
|
},
|
55
64
|
"http_token": {
|
56
65
|
"config": "configs/http_token.json",
|
57
66
|
"port": 20021, # Dedicated port
|
58
|
-
"url":
|
67
|
+
"url": "http://127.0.0.1:20021",
|
59
68
|
"auth": "api_key",
|
60
69
|
},
|
61
70
|
"https": {
|
62
71
|
"config": "configs/https_simple.json",
|
63
72
|
"port": 20022, # Dedicated port
|
64
|
-
"url":
|
73
|
+
"url": "https://127.0.0.1:20022",
|
65
74
|
"auth": "none",
|
66
75
|
},
|
67
76
|
"https_token": {
|
68
77
|
"config": "configs/https_token.json",
|
69
78
|
"port": 20023, # Dedicated port
|
70
|
-
"url":
|
79
|
+
"url": "https://127.0.0.1:20023",
|
71
80
|
"auth": "api_key",
|
72
81
|
},
|
73
82
|
"mtls": {
|
74
83
|
"config": "configs/mtls_no_roles.json",
|
75
84
|
"port": 20024, # Dedicated port
|
76
|
-
"url":
|
85
|
+
"url": "https://127.0.0.1:20024",
|
77
86
|
"auth": "certificate",
|
78
87
|
},
|
79
88
|
}
|
@@ -146,6 +155,17 @@ class SecurityTestRunner:
|
|
146
155
|
ports.append(cfg["port"])
|
147
156
|
return list(sorted(set(ports)))
|
148
157
|
|
158
|
+
def check_ports_available(self, ports: List[int]) -> Tuple[bool, List[int]]:
|
159
|
+
"""
|
160
|
+
Check if all ports in the list are available.
|
161
|
+
Returns (True, []) if all ports are free, (False, occupied_ports) otherwise.
|
162
|
+
"""
|
163
|
+
occupied_ports = []
|
164
|
+
for port in ports:
|
165
|
+
if self._port_in_use(port):
|
166
|
+
occupied_ports.append(port)
|
167
|
+
return len(occupied_ports) == 0, occupied_ports
|
168
|
+
|
149
169
|
def _validate_file(self, base: Path, path_value: Optional[str]) -> Tuple[bool, str]:
|
150
170
|
if not path_value:
|
151
171
|
return True, ""
|
@@ -229,13 +249,20 @@ class SecurityTestRunner:
|
|
229
249
|
"""Start a server in background."""
|
230
250
|
try:
|
231
251
|
print(f"🚀 Starting {name} server on port {port}...")
|
232
|
-
|
233
|
-
#
|
252
|
+
|
253
|
+
# Always ensure port is free before starting server
|
234
254
|
if self._port_in_use(port):
|
235
|
-
print(f"
|
236
|
-
|
237
|
-
|
238
|
-
|
255
|
+
print(f"🧹 Port {port} is in use, freeing it...")
|
256
|
+
self.ensure_ports_free([port])
|
257
|
+
time.sleep(1) # Give time for port to be freed
|
258
|
+
|
259
|
+
# Check again after freeing
|
260
|
+
if self._port_in_use(port):
|
261
|
+
print(
|
262
|
+
f"❌ Port {port} still in use after cleanup, cannot start {name}"
|
263
|
+
)
|
264
|
+
return None
|
265
|
+
|
239
266
|
# Start server in background
|
240
267
|
logs_dir = Path("logs")
|
241
268
|
logs_dir.mkdir(exist_ok=True)
|
@@ -293,11 +320,25 @@ class SecurityTestRunner:
|
|
293
320
|
"""Start the proxy server for server registration."""
|
294
321
|
try:
|
295
322
|
print("🚀 Starting proxy server...")
|
323
|
+
|
324
|
+
# Ensure proxy port is free
|
325
|
+
if self._port_in_use(self.proxy_port):
|
326
|
+
print(f"🧹 Proxy port {self.proxy_port} is in use, freeing it...")
|
327
|
+
self.ensure_ports_free([self.proxy_port])
|
328
|
+
time.sleep(1)
|
329
|
+
|
330
|
+
if self._port_in_use(self.proxy_port):
|
331
|
+
print(f"❌ Proxy port {self.proxy_port} still in use after cleanup")
|
332
|
+
return False
|
333
|
+
|
296
334
|
# Find the proxy server script
|
297
335
|
proxy_script = Path(__file__).parent / "run_proxy_server.py"
|
298
336
|
if not proxy_script.exists():
|
299
|
-
|
300
|
-
|
337
|
+
# Try alternative path
|
338
|
+
proxy_script = Path.cwd() / "run_proxy_server.py"
|
339
|
+
if not proxy_script.exists():
|
340
|
+
print("❌ Proxy server script not found")
|
341
|
+
return False
|
301
342
|
|
302
343
|
# Start proxy server
|
303
344
|
cmd = [
|
@@ -372,13 +413,27 @@ class SecurityTestRunner:
|
|
372
413
|
# Override SSL context for mTLS
|
373
414
|
client.create_ssl_context = client.create_ssl_context_for_mtls
|
374
415
|
async with client as client_session:
|
375
|
-
|
376
|
-
|
377
|
-
|
416
|
+
# Pass correct token for api_key authentication
|
417
|
+
if config["auth"] == "api_key":
|
418
|
+
results = await client_session.run_security_tests(
|
419
|
+
config["url"], config["auth"], token="admin-secret-key"
|
420
|
+
)
|
421
|
+
else:
|
422
|
+
results = await client_session.run_security_tests(
|
423
|
+
config["url"], config["auth"]
|
424
|
+
)
|
378
425
|
else:
|
379
426
|
# For other auth types, use default SSL context
|
380
427
|
async with SecurityTestClient(config["url"]) as client:
|
381
|
-
|
428
|
+
# Pass correct token for api_key authentication
|
429
|
+
if config["auth"] == "api_key":
|
430
|
+
results = await client.run_security_tests(
|
431
|
+
config["url"], config["auth"], token="admin-secret-key"
|
432
|
+
)
|
433
|
+
else:
|
434
|
+
results = await client.run_security_tests(
|
435
|
+
config["url"], config["auth"]
|
436
|
+
)
|
382
437
|
# Print summary for this server
|
383
438
|
passed = sum(1 for r in results if r.success)
|
384
439
|
total = len(results)
|
@@ -521,13 +576,13 @@ class SecurityTestRunner:
|
|
521
576
|
print("\n🔍 STEP 1: Complete Port Availability Check")
|
522
577
|
all_ports = self.get_all_ports()
|
523
578
|
print(f"📋 Required ports: {all_ports}")
|
524
|
-
|
579
|
+
|
525
580
|
# Check if ALL ports are available
|
526
581
|
ports_available, occupied_ports = self.check_ports_available(all_ports)
|
527
582
|
if not ports_available:
|
528
583
|
print(f"❌ CRITICAL: Ports are occupied: {occupied_ports}")
|
529
584
|
print("🧹 Attempting to free occupied ports...")
|
530
|
-
|
585
|
+
|
531
586
|
if not self.ensure_ports_free(all_ports):
|
532
587
|
print("❌ FAILED: Could not free occupied ports. Aborting tests.")
|
533
588
|
print("💡 Manual cleanup required:")
|
@@ -584,7 +639,7 @@ def main():
|
|
584
639
|
"--no-cleanup", action="store_true", help="Don't cleanup servers after tests"
|
585
640
|
)
|
586
641
|
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
|
587
|
-
|
642
|
+
parser.parse_args()
|
588
643
|
|
589
644
|
# Determine the correct configs directory
|
590
645
|
current_dir = Path.cwd()
|
@@ -11,28 +11,26 @@ Author: Vasiliy Zdanovskiy
|
|
11
11
|
email: vasilyvz@gmail.com
|
12
12
|
"""
|
13
13
|
import asyncio
|
14
|
-
import json
|
15
14
|
import os
|
16
15
|
import ssl
|
17
16
|
import sys
|
18
17
|
import time
|
19
18
|
from pathlib import Path
|
20
|
-
from typing import Dict, List, Optional
|
19
|
+
from typing import Dict, List, Optional
|
21
20
|
from dataclasses import dataclass
|
22
|
-
import aiohttp
|
23
21
|
from aiohttp import ClientSession, ClientTimeout, TCPConnector
|
24
22
|
|
25
23
|
# Add project root to path for imports
|
26
|
-
project_root = Path(__file__).parent.parent.parent
|
27
24
|
current_dir = Path(__file__).parent
|
28
25
|
parent_dir = current_dir.parent
|
29
|
-
|
26
|
+
# Only add paths that are likely to exist and be useful
|
27
|
+
if parent_dir.exists():
|
28
|
+
sys.path.insert(0, str(parent_dir))
|
30
29
|
sys.path.insert(0, str(current_dir))
|
31
|
-
sys.path.insert(0, str(parent_dir))
|
32
30
|
|
33
31
|
# Import mcp_security_framework components
|
34
32
|
try:
|
35
|
-
from mcp_security_framework import SSLManager
|
33
|
+
from mcp_security_framework import SSLManager
|
36
34
|
from mcp_security_framework.schemas.config import SSLConfig
|
37
35
|
|
38
36
|
_MCP_SECURITY_AVAILABLE = True
|
@@ -43,9 +41,6 @@ except ImportError:
|
|
43
41
|
|
44
42
|
# Import cryptography components
|
45
43
|
try:
|
46
|
-
from cryptography import x509
|
47
|
-
from cryptography.hazmat.primitives import serialization
|
48
|
-
|
49
44
|
_CRYPTOGRAPHY_AVAILABLE = True
|
50
45
|
print("✅ cryptography available")
|
51
46
|
except ImportError:
|
@@ -111,19 +106,19 @@ class SecurityTestClient:
|
|
111
106
|
"proxy": "proxy-token-123",
|
112
107
|
"invalid": "invalid-token-999",
|
113
108
|
}
|
114
|
-
# Test certificates
|
109
|
+
# Test certificates - use relative paths
|
115
110
|
self.test_certificates = {
|
116
111
|
"admin": {
|
117
|
-
"cert": "
|
118
|
-
"key": "
|
112
|
+
"cert": "certs/admin_cert.pem",
|
113
|
+
"key": "certs/admin_key.pem",
|
119
114
|
},
|
120
115
|
"user": {
|
121
|
-
"cert": "
|
122
|
-
"key": "
|
116
|
+
"cert": "certs/user_cert.pem",
|
117
|
+
"key": "certs/user_key.pem",
|
123
118
|
},
|
124
119
|
"readonly": {
|
125
|
-
"cert": "
|
126
|
-
"key": "
|
120
|
+
"cert": "certs/readonly_cert.pem",
|
121
|
+
"key": "certs/readonly_key.pem",
|
127
122
|
},
|
128
123
|
}
|
129
124
|
|
@@ -227,6 +222,7 @@ class SecurityTestClient:
|
|
227
222
|
headers = {"Content-Type": "application/json"}
|
228
223
|
if auth_type == "api_key":
|
229
224
|
token = kwargs.get("token", "test-token-123")
|
225
|
+
print(f"🔍 DEBUG: Using token: {token}")
|
230
226
|
# Provide both common header styles to maximize compatibility
|
231
227
|
headers["X-API-Key"] = token
|
232
228
|
headers["Authorization"] = f"Bearer {token}"
|
@@ -430,9 +426,7 @@ class SecurityTestClient:
|
|
430
426
|
try:
|
431
427
|
if auth_type == "certificate":
|
432
428
|
# For mTLS, test with invalid/expired certificate or no certificate
|
433
|
-
import aiohttp
|
434
429
|
from aiohttp import ClientTimeout, TCPConnector
|
435
|
-
import ssl
|
436
430
|
|
437
431
|
# Create SSL context with wrong certificate (should be rejected)
|
438
432
|
ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
@@ -450,6 +444,8 @@ class SecurityTestClient:
|
|
450
444
|
timeout = ClientTimeout(total=10) # Shorter timeout
|
451
445
|
|
452
446
|
try:
|
447
|
+
import aiohttp
|
448
|
+
|
453
449
|
async with aiohttp.ClientSession(
|
454
450
|
timeout=timeout, connector=connector
|
455
451
|
) as temp_session:
|
@@ -474,11 +470,7 @@ class SecurityTestClient:
|
|
474
470
|
error_message=f"SECURITY ISSUE: mTLS server accepted connection without client certificate (status: {response.status})",
|
475
471
|
duration=duration,
|
476
472
|
)
|
477
|
-
except (
|
478
|
-
aiohttp.ClientError,
|
479
|
-
aiohttp.ServerDisconnectedError,
|
480
|
-
asyncio.TimeoutError,
|
481
|
-
) as e:
|
473
|
+
except (Exception,) as e:
|
482
474
|
# This is expected - server should reject connections without proper certificate
|
483
475
|
duration = time.time() - start_time
|
484
476
|
return TestResult(
|
@@ -797,7 +789,7 @@ class SecurityTestClient:
|
|
797
789
|
print(f"Total Tests: {total_tests}")
|
798
790
|
print(f"Passed: {passed_tests} ✅")
|
799
791
|
print(f"Failed: {failed_tests} ❌")
|
800
|
-
print(f"Success Rate: {(passed_tests/total_tests*100):.1f}%")
|
792
|
+
print(f"Success Rate: {(passed_tests / total_tests * 100):.1f}%")
|
801
793
|
if failed_tests > 0:
|
802
794
|
print("\n❌ Failed Tests:")
|
803
795
|
for result in self.test_results:
|
@@ -25,7 +25,7 @@ import sys
|
|
25
25
|
import argparse
|
26
26
|
import json
|
27
27
|
from pathlib import Path
|
28
|
-
from typing import Dict, List, Any,
|
28
|
+
from typing import Dict, List, Any, Tuple
|
29
29
|
|
30
30
|
# Import mcp_security_framework
|
31
31
|
try:
|
@@ -191,8 +191,10 @@ def _get_package_paths() -> tuple[Path, Path]:
|
|
191
191
|
# We need to go up to the package root: .venv/lib/python3.x/site-packages/mcp_proxy_adapter/
|
192
192
|
pkg_root = Path(__file__).resolve().parents[1]
|
193
193
|
examples_path = pkg_root / "examples"
|
194
|
-
utils_path =
|
195
|
-
|
194
|
+
utils_path = (
|
195
|
+
pkg_root / "examples" / "scripts"
|
196
|
+
) # utils scripts are in examples/scripts in the package
|
197
|
+
|
196
198
|
return examples_path, utils_path
|
197
199
|
|
198
200
|
|
@@ -440,12 +442,12 @@ async def register_server(request: Request):
|
|
440
442
|
try:
|
441
443
|
data = await request.json()
|
442
444
|
print(f"✅ Received registration request: {data}")
|
443
|
-
|
445
|
+
|
444
446
|
# Check if client certificate is present
|
445
447
|
client_cert = request.client
|
446
448
|
if client_cert:
|
447
449
|
print(f"✅ Client certificate verified: {client_cert}")
|
448
|
-
|
450
|
+
|
449
451
|
return JSONResponse(
|
450
452
|
status_code=200,
|
451
453
|
content={
|
@@ -489,14 +491,14 @@ async def main():
|
|
489
491
|
print(" POST /register - Register server")
|
490
492
|
print(" GET /health - Health check")
|
491
493
|
print("⚡ Press Ctrl+C to stop\\n")
|
492
|
-
|
494
|
+
|
493
495
|
# Configure Hypercorn
|
494
496
|
config = hypercorn.config.Config()
|
495
497
|
config.bind = ["127.0.0.1:20005"]
|
496
498
|
config.certfile = "certs/localhost_server.crt"
|
497
499
|
config.keyfile = "keys/server_key.pem"
|
498
500
|
config.loglevel = "info"
|
499
|
-
|
501
|
+
|
500
502
|
# Run server with mTLS using Hypercorn
|
501
503
|
await hypercorn.asyncio.serve(app, config)
|
502
504
|
|
@@ -532,7 +534,7 @@ def test_proxy_registration():
|
|
532
534
|
"""Test proxy registration with SSL configuration."""
|
533
535
|
print("🧪 Testing Proxy Registration SSL Configuration Fix")
|
534
536
|
print("=" * 60)
|
535
|
-
|
537
|
+
|
536
538
|
# Kill any existing process on port 20005
|
537
539
|
print("🧹 Killing any existing process on port 20005...")
|
538
540
|
try:
|
@@ -540,21 +542,27 @@ def test_proxy_registration():
|
|
540
542
|
except FileNotFoundError:
|
541
543
|
# fuser not available, try with lsof
|
542
544
|
try:
|
543
|
-
|
545
|
+
# Get PIDs using lsof
|
546
|
+
result = subprocess.run(["lsof", "-ti:20005"], capture_output=True, text=True, check=False)
|
547
|
+
if result.returncode == 0 and result.stdout.strip():
|
548
|
+
pids = result.stdout.strip().split('\\n')
|
549
|
+
for pid in pids:
|
550
|
+
if pid.strip():
|
551
|
+
subprocess.run(["kill", "-9", pid.strip()], check=False, capture_output=True)
|
544
552
|
except:
|
545
553
|
pass
|
546
|
-
|
554
|
+
|
547
555
|
# Start proxy server
|
548
556
|
print("🚀 Starting test proxy server...")
|
549
557
|
proxy_process = subprocess.Popen([
|
550
558
|
sys.executable, "test_proxy_server.py"
|
551
559
|
], cwd=Path(__file__).parent)
|
552
|
-
|
560
|
+
|
553
561
|
try:
|
554
562
|
# Wait for server to start
|
555
563
|
print("⏳ Waiting for proxy server to start...")
|
556
564
|
time.sleep(5)
|
557
|
-
|
565
|
+
|
558
566
|
# Test proxy server health
|
559
567
|
print("🔍 Testing proxy server health...")
|
560
568
|
try:
|
@@ -571,19 +579,19 @@ def test_proxy_registration():
|
|
571
579
|
except Exception as e:
|
572
580
|
print(f"❌ Failed to connect to proxy server: {e}")
|
573
581
|
return False
|
574
|
-
|
582
|
+
|
575
583
|
# Test mTLS server with registration
|
576
584
|
print("🚀 Starting mTLS server with proxy registration...")
|
577
585
|
server_process = subprocess.Popen([
|
578
586
|
sys.executable, "-m", "mcp_proxy_adapter",
|
579
587
|
"--config", "configs/test_proxy_registration.json"
|
580
588
|
], cwd=Path(__file__).parent)
|
581
|
-
|
589
|
+
|
582
590
|
try:
|
583
591
|
# Wait for server to start and attempt registration
|
584
592
|
print("⏳ Waiting for server to start and register...")
|
585
593
|
time.sleep(10)
|
586
|
-
|
594
|
+
|
587
595
|
# Check if server is running
|
588
596
|
if server_process.poll() is None:
|
589
597
|
print("✅ mTLS server started successfully")
|
@@ -592,13 +600,13 @@ def test_proxy_registration():
|
|
592
600
|
else:
|
593
601
|
print("❌ mTLS server failed to start")
|
594
602
|
return False
|
595
|
-
|
603
|
+
|
596
604
|
finally:
|
597
605
|
# Clean up server process
|
598
606
|
if server_process.poll() is None:
|
599
607
|
server_process.terminate()
|
600
608
|
server_process.wait()
|
601
|
-
|
609
|
+
|
602
610
|
finally:
|
603
611
|
# Clean up proxy process
|
604
612
|
if proxy_process.poll() is None:
|
@@ -609,7 +617,7 @@ def test_proxy_registration():
|
|
609
617
|
def main():
|
610
618
|
"""Run the test."""
|
611
619
|
success = test_proxy_registration()
|
612
|
-
|
620
|
+
|
613
621
|
if success:
|
614
622
|
print("\\n🎉 All tests passed! Proxy registration SSL fix is working correctly.")
|
615
623
|
return 0
|
@@ -647,30 +655,23 @@ def generate_enhanced_configurations(output_dir: Path) -> None:
|
|
647
655
|
"debug": False,
|
648
656
|
"log_level": "INFO",
|
649
657
|
"workers": 1,
|
650
|
-
"reload": False
|
651
|
-
},
|
652
|
-
"ssl": {
|
653
|
-
"enabled": False
|
658
|
+
"reload": False,
|
654
659
|
},
|
660
|
+
"ssl": {"enabled": False},
|
655
661
|
"security": {
|
656
662
|
"enabled": True,
|
657
663
|
"auth": {
|
658
664
|
"enabled": True,
|
659
|
-
"methods": [
|
660
|
-
"api_key"
|
661
|
-
],
|
665
|
+
"methods": ["api_key"],
|
662
666
|
"api_keys": {
|
663
667
|
"admin-token-123": "admin",
|
664
668
|
"user-token-456": "user",
|
665
669
|
"readonly-token-789": "readonly",
|
666
670
|
"guest-token-abc": "guest",
|
667
|
-
"proxy-token-def": "proxy"
|
668
|
-
}
|
671
|
+
"proxy-token-def": "proxy",
|
672
|
+
},
|
669
673
|
},
|
670
|
-
"permissions": {
|
671
|
-
"enabled": True,
|
672
|
-
"roles_file": "configs/roles.json"
|
673
|
-
}
|
674
|
+
"permissions": {"enabled": True, "roles_file": "configs/roles.json"},
|
674
675
|
},
|
675
676
|
"registration": {
|
676
677
|
"enabled": True,
|
@@ -681,21 +682,13 @@ def generate_enhanced_configurations(output_dir: Path) -> None:
|
|
681
682
|
"token_auth",
|
682
683
|
"roles",
|
683
684
|
"registration",
|
684
|
-
"heartbeat"
|
685
|
+
"heartbeat",
|
685
686
|
],
|
686
687
|
"retry_count": 3,
|
687
688
|
"retry_delay": 5,
|
688
|
-
"heartbeat": {
|
689
|
-
"enabled": True,
|
690
|
-
"interval": 30
|
691
|
-
}
|
689
|
+
"heartbeat": {"enabled": True, "interval": 30},
|
692
690
|
},
|
693
|
-
"protocols": {
|
694
|
-
"enabled": True,
|
695
|
-
"allowed_protocols": [
|
696
|
-
"http"
|
697
|
-
]
|
698
|
-
}
|
691
|
+
"protocols": {"enabled": True, "allowed_protocols": ["http"]},
|
699
692
|
}
|
700
693
|
}
|
701
694
|
|
@@ -886,30 +879,27 @@ def setup_test_environment(output_dir: Path) -> None:
|
|
886
879
|
test_files = [
|
887
880
|
"create_test_configs.py",
|
888
881
|
"run_security_tests.py",
|
889
|
-
"run_proxy_server.py"
|
882
|
+
"run_proxy_server.py",
|
890
883
|
]
|
891
884
|
for test_file in test_files:
|
892
885
|
test_file_src = examples_src_root / test_file
|
893
886
|
if test_file_src.exists():
|
894
887
|
shutil.copy2(test_file_src, output_dir)
|
895
888
|
print(f"✅ Copied {test_file}")
|
896
|
-
|
889
|
+
|
897
890
|
# Create comprehensive_config.json if it doesn't exist
|
898
891
|
comprehensive_config_dst = output_dir / "comprehensive_config.json"
|
899
892
|
if not comprehensive_config_dst.exists():
|
900
893
|
# Create a basic comprehensive config
|
901
894
|
comprehensive_config = {
|
902
895
|
"uuid": "79db1fa0-ff4e-4695-8c94-1d5ac470b613",
|
903
|
-
"server": {
|
904
|
-
"host": "127.0.0.1",
|
905
|
-
"port": 20001
|
906
|
-
},
|
896
|
+
"server": {"host": "127.0.0.1", "port": 20001},
|
907
897
|
"ssl": {
|
908
898
|
"enabled": False,
|
909
899
|
"cert_file": "certs/localhost_server.crt",
|
910
900
|
"key_file": "keys/localhost_server.key",
|
911
901
|
"ca_cert": "certs/mcp_proxy_adapter_ca_ca.crt",
|
912
|
-
"verify_client": False
|
902
|
+
"verify_client": False,
|
913
903
|
},
|
914
904
|
"security": {
|
915
905
|
"enabled": True,
|
@@ -919,22 +909,19 @@ def setup_test_environment(output_dir: Path) -> None:
|
|
919
909
|
"api_keys": {
|
920
910
|
"admin-token-123": "admin",
|
921
911
|
"user-token-456": "user",
|
922
|
-
"readonly-token-789": "readonly"
|
923
|
-
}
|
912
|
+
"readonly-token-789": "readonly",
|
913
|
+
},
|
924
914
|
},
|
925
|
-
"permissions": {
|
926
|
-
"enabled": True,
|
927
|
-
"roles_file": "roles.json"
|
928
|
-
}
|
915
|
+
"permissions": {"enabled": True, "roles_file": "roles.json"},
|
929
916
|
},
|
930
917
|
"protocols": {
|
931
918
|
"enabled": True,
|
932
919
|
"default_protocol": "http",
|
933
|
-
"allowed_protocols": ["http"]
|
934
|
-
}
|
920
|
+
"allowed_protocols": ["http"],
|
921
|
+
},
|
935
922
|
}
|
936
|
-
|
937
|
-
with open(comprehensive_config_dst,
|
923
|
+
|
924
|
+
with open(comprehensive_config_dst, "w", encoding="utf-8") as f:
|
938
925
|
json.dump(comprehensive_config, f, indent=2)
|
939
926
|
print("✅ Created comprehensive_config.json")
|
940
927
|
else:
|
@@ -951,21 +938,21 @@ def setup_test_environment(output_dir: Path) -> None:
|
|
951
938
|
"roles": {
|
952
939
|
"admin": {
|
953
940
|
"permissions": ["*"],
|
954
|
-
"description": "Full access to all commands"
|
941
|
+
"description": "Full access to all commands",
|
955
942
|
},
|
956
943
|
"user": {
|
957
944
|
"permissions": ["echo", "health", "help"],
|
958
|
-
"description": "Basic user permissions"
|
945
|
+
"description": "Basic user permissions",
|
959
946
|
},
|
960
947
|
"readonly": {
|
961
948
|
"permissions": ["health", "help"],
|
962
|
-
"description": "Read-only access"
|
963
|
-
}
|
949
|
+
"description": "Read-only access",
|
950
|
+
},
|
964
951
|
}
|
965
952
|
}
|
966
|
-
|
953
|
+
|
967
954
|
roles_dst = output_dir / "roles.json"
|
968
|
-
with open(roles_dst,
|
955
|
+
with open(roles_dst, "w", encoding="utf-8") as f:
|
969
956
|
json.dump(roles_config, f, indent=2)
|
970
957
|
print("✅ Created roles.json in root directory")
|
971
958
|
|
@@ -1102,10 +1089,10 @@ def generate_certificates_with_framework(output_dir: Path) -> bool:
|
|
1102
1089
|
roles=roles,
|
1103
1090
|
permissions=permissions,
|
1104
1091
|
ca_cert_path=cert_pair.certificate_path,
|
1105
|
-
ca_key_path=
|
1092
|
+
ca_key_path=cert_pair.private_key_path,
|
1106
1093
|
)
|
1107
|
-
|
1108
|
-
if not
|
1094
|
+
client_cert_pair = cert_manager.create_client_certificate(client_config)
|
1095
|
+
if not client_cert_pair or not client_cert_pair.certificate_path:
|
1109
1096
|
print(
|
1110
1097
|
(
|
1111
1098
|
"❌ Failed to create client certificate {}: "
|
@@ -1134,33 +1121,36 @@ def run_full_test_suite(target_root: Path) -> bool:
|
|
1134
1121
|
print("\n" + "=" * 60)
|
1135
1122
|
print("🚀 AUTOMATICALLY RUNNING FULL TEST SUITE")
|
1136
1123
|
print("=" * 60)
|
1137
|
-
|
1124
|
+
|
1138
1125
|
try:
|
1139
1126
|
# Change to target directory
|
1140
1127
|
original_cwd = Path.cwd()
|
1141
1128
|
os.chdir(target_root)
|
1142
|
-
|
1129
|
+
|
1143
1130
|
# Run the full test suite
|
1144
|
-
result = subprocess.run(
|
1145
|
-
sys.executable, "run_full_test_suite.py"
|
1146
|
-
|
1147
|
-
|
1131
|
+
result = subprocess.run(
|
1132
|
+
[sys.executable, "run_full_test_suite.py"],
|
1133
|
+
capture_output=True,
|
1134
|
+
text=True,
|
1135
|
+
timeout=300,
|
1136
|
+
) # 5 minute timeout
|
1137
|
+
|
1148
1138
|
# Print output
|
1149
1139
|
if result.stdout:
|
1150
1140
|
print("📋 Test Suite Output:")
|
1151
1141
|
print(result.stdout)
|
1152
|
-
|
1142
|
+
|
1153
1143
|
if result.stderr:
|
1154
1144
|
print("⚠️ Test Suite Warnings/Errors:")
|
1155
1145
|
print(result.stderr)
|
1156
|
-
|
1146
|
+
|
1157
1147
|
if result.returncode == 0:
|
1158
1148
|
print("🎉 FULL TEST SUITE COMPLETED SUCCESSFULLY!")
|
1159
1149
|
return True
|
1160
1150
|
else:
|
1161
1151
|
print(f"❌ FULL TEST SUITE FAILED (exit code: {result.returncode})")
|
1162
1152
|
return False
|
1163
|
-
|
1153
|
+
|
1164
1154
|
except subprocess.TimeoutExpired:
|
1165
1155
|
print("⏰ Test suite timed out after 5 minutes")
|
1166
1156
|
return False
|
@@ -1175,21 +1165,21 @@ def run_full_test_suite(target_root: Path) -> bool:
|
|
1175
1165
|
def validate_output_directory(output_dir: Path) -> bool:
|
1176
1166
|
"""
|
1177
1167
|
Validate output directory for test environment setup.
|
1178
|
-
|
1168
|
+
|
1179
1169
|
Args:
|
1180
1170
|
output_dir: Path to the target directory
|
1181
|
-
|
1171
|
+
|
1182
1172
|
Returns:
|
1183
1173
|
True if directory is valid for setup, False otherwise
|
1184
1174
|
"""
|
1185
1175
|
output_dir = output_dir.resolve()
|
1186
|
-
|
1176
|
+
|
1187
1177
|
# Check if directory exists
|
1188
1178
|
if output_dir.exists():
|
1189
1179
|
if not output_dir.is_dir():
|
1190
1180
|
print(f"❌ Path exists but is not a directory: {output_dir}")
|
1191
1181
|
return False
|
1192
|
-
|
1182
|
+
|
1193
1183
|
# Check if directory is empty
|
1194
1184
|
try:
|
1195
1185
|
contents = list(output_dir.iterdir())
|
@@ -1216,7 +1206,7 @@ def validate_output_directory(output_dir: Path) -> bool:
|
|
1216
1206
|
except Exception as e:
|
1217
1207
|
print(f"❌ Failed to create directory {output_dir}: {e}")
|
1218
1208
|
return False
|
1219
|
-
|
1209
|
+
|
1220
1210
|
return True
|
1221
1211
|
|
1222
1212
|
|
@@ -1226,7 +1216,7 @@ def check_ports_available() -> bool:
|
|
1226
1216
|
Returns True if all ports are free, False otherwise.
|
1227
1217
|
"""
|
1228
1218
|
import socket
|
1229
|
-
|
1219
|
+
|
1230
1220
|
# Ports used by the test suite - UPDATED with dedicated ports
|
1231
1221
|
test_ports = [
|
1232
1222
|
20010, # proxy_port
|
@@ -1238,17 +1228,17 @@ def check_ports_available() -> bool:
|
|
1238
1228
|
20025, # mtls_simple
|
1239
1229
|
20026, # mtls_with_roles
|
1240
1230
|
20005, # test_proxy_server
|
1241
|
-
3006,
|
1231
|
+
3006, # proxy registration
|
1242
1232
|
]
|
1243
|
-
|
1233
|
+
|
1244
1234
|
occupied_ports = []
|
1245
|
-
|
1235
|
+
|
1246
1236
|
print("🔍 Checking port availability...")
|
1247
1237
|
for port in test_ports:
|
1248
1238
|
try:
|
1249
1239
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
1250
1240
|
sock.settimeout(1)
|
1251
|
-
result = sock.connect_ex((
|
1241
|
+
result = sock.connect_ex(("127.0.0.1", port))
|
1252
1242
|
if result == 0:
|
1253
1243
|
occupied_ports.append(port)
|
1254
1244
|
print(f" ❌ Port {port} is occupied")
|
@@ -1257,9 +1247,11 @@ def check_ports_available() -> bool:
|
|
1257
1247
|
except Exception as e:
|
1258
1248
|
print(f" ⚠️ Could not check port {port}: {e}")
|
1259
1249
|
occupied_ports.append(port)
|
1260
|
-
|
1250
|
+
|
1261
1251
|
if occupied_ports:
|
1262
|
-
print(
|
1252
|
+
print(
|
1253
|
+
f"\n❌ CRITICAL: {len(occupied_ports)} ports are occupied: {occupied_ports}"
|
1254
|
+
)
|
1263
1255
|
print("💡 Please free these ports before running the test suite:")
|
1264
1256
|
for port in occupied_ports:
|
1265
1257
|
print(f" - Port {port}: kill processes using this port")
|
@@ -1267,7 +1259,7 @@ def check_ports_available() -> bool:
|
|
1267
1259
|
for port in occupied_ports:
|
1268
1260
|
print(f" fuser -k {port}/tcp")
|
1269
1261
|
return False
|
1270
|
-
|
1262
|
+
|
1271
1263
|
print(f"✅ All {len(test_ports)} required ports are available")
|
1272
1264
|
return True
|
1273
1265
|
|
@@ -1294,32 +1286,33 @@ def main() -> int:
|
|
1294
1286
|
"--skip-tests", action="store_true", help="Skip running the full test suite"
|
1295
1287
|
)
|
1296
1288
|
args = parser.parse_args()
|
1297
|
-
|
1289
|
+
|
1298
1290
|
# FIRST: Check port availability - if this fails, don't proceed
|
1299
1291
|
print("🔍 STEP 1: Port Availability Check")
|
1300
1292
|
if not check_ports_available():
|
1301
1293
|
print("\n❌ FAILED: Required ports are occupied. Aborting setup.")
|
1302
1294
|
print("💡 Please free the occupied ports and try again.")
|
1303
1295
|
return 1
|
1304
|
-
|
1296
|
+
|
1305
1297
|
try:
|
1306
1298
|
# Determine target directory
|
1307
1299
|
if args.output_dir is None:
|
1308
1300
|
# Create auto-generated directory in /tmp
|
1309
1301
|
import tempfile
|
1310
1302
|
import time
|
1303
|
+
|
1311
1304
|
timestamp = int(time.time())
|
1312
1305
|
target_root = Path(tempfile.gettempdir()) / f"mcp_test_env_{timestamp}"
|
1313
1306
|
print(f"🔧 Auto-generating test environment directory: {target_root}")
|
1314
1307
|
else:
|
1315
1308
|
target_root = Path(args.output_dir)
|
1316
|
-
|
1309
|
+
|
1317
1310
|
# Validate output directory
|
1318
1311
|
print(f"🔍 Validating output directory: {target_root}")
|
1319
1312
|
if not validate_output_directory(target_root):
|
1320
1313
|
print("\n❌ Directory validation failed. Exiting.")
|
1321
1314
|
return 1
|
1322
|
-
|
1315
|
+
|
1323
1316
|
print(f"✅ Directory validation passed: {target_root}")
|
1324
1317
|
setup_test_environment(target_root)
|
1325
1318
|
|
@@ -1333,7 +1326,7 @@ def main() -> int:
|
|
1333
1326
|
"⚠️ Skipping certificate generation (mcp_security_framework "
|
1334
1327
|
"not available)"
|
1335
1328
|
)
|
1336
|
-
|
1329
|
+
|
1337
1330
|
# Run full test suite if not skipped
|
1338
1331
|
if not args.skip_tests:
|
1339
1332
|
test_success = run_full_test_suite(target_root)
|
@@ -1342,7 +1335,7 @@ def main() -> int:
|
|
1342
1335
|
return 1
|
1343
1336
|
else:
|
1344
1337
|
print("⚠️ Skipping test suite execution (--skip-tests specified)")
|
1345
|
-
|
1338
|
+
|
1346
1339
|
except Exception as e:
|
1347
1340
|
print(
|
1348
1341
|
"❌ Error setting up test environment: {}".format(e),
|
@@ -1357,7 +1350,7 @@ def main() -> int:
|
|
1357
1350
|
print("\n" + "=" * 60)
|
1358
1351
|
print("✅ ENHANCED TEST ENVIRONMENT SETUP COMPLETED SUCCESSFULLY")
|
1359
1352
|
print("=" * 60)
|
1360
|
-
|
1353
|
+
|
1361
1354
|
if not args.skip_tests:
|
1362
1355
|
print("\n🎉 ALL TESTS PASSED - Environment is ready for use!")
|
1363
1356
|
else:
|
@@ -1376,7 +1369,7 @@ def main() -> int:
|
|
1376
1369
|
print(" python -m mcp_proxy_adapter.examples.run_security_tests")
|
1377
1370
|
print("\n7. Generate additional certificates (if needed):")
|
1378
1371
|
print(" python scripts/create_certificates_simple.py")
|
1379
|
-
|
1372
|
+
|
1380
1373
|
print("=" * 60)
|
1381
1374
|
return 0
|
1382
1375
|
|
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.4.
|
3
|
+
Version: 6.4.39
|
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
|
@@ -4,7 +4,7 @@ mcp_proxy_adapter/config.py,sha256=-7iVS0mUWWKNeao7nqTAFlUD6FcMwRlDkchN7OwYsr0,2
|
|
4
4
|
mcp_proxy_adapter/custom_openapi.py,sha256=yLle4CntYK9wpivgn9NflZyJhy-YNrmWjJzt0ai5nP0,14672
|
5
5
|
mcp_proxy_adapter/main.py,sha256=idp3KUR7CT7kTXLVPvvclJlNnt8d_HYl8_jY98uknmo,4677
|
6
6
|
mcp_proxy_adapter/openapi.py,sha256=2UZOI09ZDRJuBYBjKbMyb2U4uASszoCMD5o_4ktRpvg,13480
|
7
|
-
mcp_proxy_adapter/version.py,sha256=
|
7
|
+
mcp_proxy_adapter/version.py,sha256=fEv9yyAT-nidoRbv5rOSNSK2TPzzpGMl5e_rgcDUiWQ,75
|
8
8
|
mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
mcp_proxy_adapter/api/app.py,sha256=UQ7_m-LbUzKuuPJPxS_69ahANUQ5rnPwoddQ2MMXNkg,33941
|
10
10
|
mcp_proxy_adapter/api/handlers.py,sha256=iyFGoEuUS1wxbV1ELA0zmaxIyQR7j4zw-4MrD-uIO6E,8294
|
@@ -84,7 +84,7 @@ mcp_proxy_adapter/core/unified_config_adapter.py,sha256=zBGYdLDZ3G8f3Y9tmtm0Ne0U
|
|
84
84
|
mcp_proxy_adapter/core/utils.py,sha256=wBdDYBDWQ6zbwrnl9tykHjo0FjJVsLT_x8Bjk1lZX60,3270
|
85
85
|
mcp_proxy_adapter/examples/__init__.py,sha256=k1F-EotAFbJ3JvK_rNgiH4bUztmxIWtYn0AfbAZ1ZGs,450
|
86
86
|
mcp_proxy_adapter/examples/create_certificates_simple.py,sha256=xoa4VtKzb9y7Mn8VqcK-uH2q7Bf89vrWG6G3LQmhJng,27086
|
87
|
-
mcp_proxy_adapter/examples/create_test_configs.py,sha256=
|
87
|
+
mcp_proxy_adapter/examples/create_test_configs.py,sha256=k7-GycHP96CZFry7EXwkQCViPlr_7jq-f18I9kVWN6c,11253
|
88
88
|
mcp_proxy_adapter/examples/debug_request_state.py,sha256=Z3Gy2-fWtu7KIV9OkzGDLVz7TpL_h9V_99ica40uQBU,4489
|
89
89
|
mcp_proxy_adapter/examples/debug_role_chain.py,sha256=GLVXC2fJUwP8UJnXHchd1t-H53cjWLJI3RqTPrKmaak,8750
|
90
90
|
mcp_proxy_adapter/examples/demo_client.py,sha256=en2Rtb70B1sQmhL-vdQ4PDpKNNl_mfll2YCFT_jFCAg,10191
|
@@ -94,12 +94,12 @@ mcp_proxy_adapter/examples/generate_certificates_and_tokens.py,sha256=hUCoJH3fy5
|
|
94
94
|
mcp_proxy_adapter/examples/generate_test_configs.py,sha256=FWg_QFJAWinI1lw05RccX4_VbhsCBEKPpZA6I9v6KAs,14379
|
95
95
|
mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=vemRhftnjbiOBCJkmtDGqlWQ8syTG0a8755GCOnaQsg,12503
|
96
96
|
mcp_proxy_adapter/examples/run_example.py,sha256=yp-a6HIrSk3ddQmbn0KkuKwErId0aNfj028TE6U-zmY,2626
|
97
|
-
mcp_proxy_adapter/examples/run_full_test_suite.py,sha256=
|
97
|
+
mcp_proxy_adapter/examples/run_full_test_suite.py,sha256=QI4a7vTDovHTVd8BDeRAWsCNZp5aTtrlp7NE2LZU5bA,20143
|
98
98
|
mcp_proxy_adapter/examples/run_proxy_server.py,sha256=SBLSSY2F_VEBQD3MsCE_Pa9xFE6Sszr3vHdE9QOEN4Y,5242
|
99
|
-
mcp_proxy_adapter/examples/run_security_tests.py,sha256=
|
99
|
+
mcp_proxy_adapter/examples/run_security_tests.py,sha256=3mgp6fbPknI2fljpuedvtwoY1DzT_-UlOR45fHrkO0A,26215
|
100
100
|
mcp_proxy_adapter/examples/run_security_tests_fixed.py,sha256=2BKMT0_-FhmcZA73hdQOt2XR7Cgb9Sq8qBI88BkwAAA,10934
|
101
|
-
mcp_proxy_adapter/examples/security_test_client.py,sha256=
|
102
|
-
mcp_proxy_adapter/examples/setup_test_environment.py,sha256=
|
101
|
+
mcp_proxy_adapter/examples/security_test_client.py,sha256=o4XhXCDZPaGVNjOSc0qm8onouj_ZenACz9aSEkvzbRc,35313
|
102
|
+
mcp_proxy_adapter/examples/setup_test_environment.py,sha256=gXo_ZIjmZC6WLQG0deng4w-vLfaSLmHTk29b5dEBiAw,45334
|
103
103
|
mcp_proxy_adapter/examples/test_config.py,sha256=ekEoUZe9q484vU_0IxOVhQdNMVJXG3IpmQpP--VmuDI,6491
|
104
104
|
mcp_proxy_adapter/examples/test_config_generator.py,sha256=PBXk1V_awJ-iBlbE66Pme5sQwu6CJDxkmqgm8uPtM58,4091
|
105
105
|
mcp_proxy_adapter/examples/test_examples.py,sha256=CYlVatdHUVC_rwv4NsvxFG3GXiKIyxPDUH43BOJHjrU,12330
|
@@ -121,8 +121,8 @@ mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py,sha25
|
|
121
121
|
mcp_proxy_adapter/examples/scripts/config_generator.py,sha256=SKFlRRCE_pEHGbfjDuzfKpvV2DMwG6lRfK90uJwRlJM,33410
|
122
122
|
mcp_proxy_adapter/examples/scripts/create_certificates_simple.py,sha256=yCWdUIhMSDPwoPhuLR9rhPdf7jLN5hCjzNfYYgVyHnw,27769
|
123
123
|
mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py,sha256=hUCoJH3fy5WeR_YMHj-_W0mR0ZKUWqewH4FVN3yWyrM,17972
|
124
|
-
mcp_proxy_adapter-6.4.
|
125
|
-
mcp_proxy_adapter-6.4.
|
126
|
-
mcp_proxy_adapter-6.4.
|
127
|
-
mcp_proxy_adapter-6.4.
|
128
|
-
mcp_proxy_adapter-6.4.
|
124
|
+
mcp_proxy_adapter-6.4.39.dist-info/METADATA,sha256=M2i7654bHp6n3l5nQOCgZPZ8Cje5mMSGWedtUek1bvs,6087
|
125
|
+
mcp_proxy_adapter-6.4.39.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
126
|
+
mcp_proxy_adapter-6.4.39.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
|
127
|
+
mcp_proxy_adapter-6.4.39.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
|
128
|
+
mcp_proxy_adapter-6.4.39.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|