mcp-proxy-adapter 6.3.3__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 +12 -2
- 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.3.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.3.dist-info/RECORD +0 -143
- {mcp_proxy_adapter-6.3.3.dist-info ā mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.3.dist-info ā mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.3.dist-info ā mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.3.3.dist-info ā mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -12,9 +12,10 @@ import time
|
|
12
12
|
from pathlib import Path
|
13
13
|
from typing import List, Dict, Optional
|
14
14
|
|
15
|
+
|
15
16
|
class FullTestSuiteRunner:
|
16
17
|
"""Comprehensive test suite runner that automates the entire testing process."""
|
17
|
-
|
18
|
+
|
18
19
|
def __init__(self):
|
19
20
|
"""Initialize the test suite runner."""
|
20
21
|
self.working_dir = Path.cwd()
|
@@ -22,92 +23,109 @@ class FullTestSuiteRunner:
|
|
22
23
|
self.certs_dir = self.working_dir / "certs"
|
23
24
|
self.keys_dir = self.working_dir / "keys"
|
24
25
|
self.roles_file = self.working_dir / "configs" / "roles.json"
|
25
|
-
|
26
|
+
|
26
27
|
def print_step(self, step: str, description: str):
|
27
28
|
"""Print a formatted step header."""
|
28
29
|
print(f"\n{'='*60}")
|
29
30
|
print(f"š§ STEP {step}: {description}")
|
30
31
|
print(f"{'='*60}")
|
31
|
-
|
32
|
+
|
32
33
|
def print_success(self, message: str):
|
33
34
|
"""Print a success message."""
|
34
35
|
print(f"ā
{message}")
|
35
|
-
|
36
|
+
|
36
37
|
def print_error(self, message: str):
|
37
38
|
"""Print an error message."""
|
38
39
|
print(f"ā {message}")
|
39
|
-
|
40
|
+
|
40
41
|
def print_info(self, message: str):
|
41
42
|
"""Print an info message."""
|
42
43
|
print(f"ā¹ļø {message}")
|
43
|
-
|
44
|
+
|
44
45
|
def check_environment(self) -> bool:
|
45
46
|
"""Check if the environment is properly set up."""
|
46
47
|
self.print_step("1", "Environment Validation")
|
47
|
-
|
48
|
+
|
48
49
|
# Check if we're in a virtual environment
|
49
|
-
if not hasattr(sys,
|
50
|
+
if not hasattr(sys, "real_prefix") and not (
|
51
|
+
hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
|
52
|
+
):
|
50
53
|
self.print_error("Not running in a virtual environment!")
|
51
54
|
self.print_info("Please activate your virtual environment first:")
|
52
55
|
self.print_info(" source venv/bin/activate # or .venv/bin/activate")
|
53
56
|
return False
|
54
|
-
|
57
|
+
|
55
58
|
self.print_success("Virtual environment is active")
|
56
|
-
|
59
|
+
|
57
60
|
# Check if mcp_proxy_adapter is installed
|
58
61
|
try:
|
59
62
|
import mcp_proxy_adapter
|
60
|
-
|
63
|
+
|
64
|
+
self.print_success(
|
65
|
+
f"mcp_proxy_adapter is installed (version: {mcp_proxy_adapter.__version__})"
|
66
|
+
)
|
61
67
|
except ImportError:
|
62
68
|
self.print_error("mcp_proxy_adapter is not installed!")
|
63
69
|
self.print_info("Please install it first:")
|
64
70
|
self.print_info(" pip install mcp_proxy_adapter")
|
65
71
|
return False
|
66
|
-
|
72
|
+
|
67
73
|
# Check Python version
|
68
74
|
python_version = sys.version_info
|
69
75
|
if python_version.major >= 3 and python_version.minor >= 8:
|
70
|
-
self.print_success(
|
76
|
+
self.print_success(
|
77
|
+
f"Python version: {python_version.major}.{python_version.minor}.{python_version.micro}"
|
78
|
+
)
|
71
79
|
else:
|
72
|
-
self.print_error(
|
80
|
+
self.print_error(
|
81
|
+
f"Python {python_version.major}.{python_version.minor} is not supported. Need Python 3.8+"
|
82
|
+
)
|
73
83
|
return False
|
74
|
-
|
84
|
+
|
75
85
|
return True
|
76
|
-
|
86
|
+
|
77
87
|
def create_directories(self) -> bool:
|
78
88
|
"""Create necessary directories for testing."""
|
79
89
|
self.print_step("2", "Directory Creation")
|
80
|
-
|
90
|
+
|
81
91
|
try:
|
82
92
|
# Create configs directory
|
83
93
|
self.configs_dir.mkdir(exist_ok=True)
|
84
|
-
self.print_success(
|
85
|
-
|
94
|
+
self.print_success(
|
95
|
+
f"Created/verified configs directory: {self.configs_dir}"
|
96
|
+
)
|
97
|
+
|
86
98
|
# Create certs directory
|
87
99
|
self.certs_dir.mkdir(exist_ok=True)
|
88
100
|
self.print_success(f"Created/verified certs directory: {self.certs_dir}")
|
89
|
-
|
101
|
+
|
90
102
|
# Create keys directory
|
91
103
|
self.keys_dir.mkdir(exist_ok=True)
|
92
104
|
self.print_success(f"Created/verified keys directory: {self.keys_dir}")
|
93
|
-
|
105
|
+
|
94
106
|
return True
|
95
|
-
|
107
|
+
|
96
108
|
except Exception as e:
|
97
109
|
self.print_error(f"Failed to create directories: {e}")
|
98
110
|
return False
|
99
|
-
|
111
|
+
|
100
112
|
def generate_certificates(self) -> bool:
|
101
113
|
"""Generate SSL certificates for testing."""
|
102
114
|
self.print_step("3", "Certificate Generation")
|
103
|
-
|
115
|
+
|
104
116
|
try:
|
105
117
|
# Run certificate generation script
|
106
|
-
cmd = [
|
118
|
+
cmd = [
|
119
|
+
sys.executable,
|
120
|
+
"-m",
|
121
|
+
"mcp_proxy_adapter.examples.create_certificates_simple",
|
122
|
+
]
|
107
123
|
self.print_info("Running certificate generation script...")
|
108
|
-
|
109
|
-
result = subprocess.run(
|
110
|
-
|
124
|
+
|
125
|
+
result = subprocess.run(
|
126
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
127
|
+
)
|
128
|
+
|
111
129
|
if result.returncode == 0:
|
112
130
|
self.print_success("Certificates generated successfully")
|
113
131
|
if result.stdout:
|
@@ -119,22 +137,28 @@ class FullTestSuiteRunner:
|
|
119
137
|
print("Error output:")
|
120
138
|
print(result.stderr)
|
121
139
|
return False
|
122
|
-
|
140
|
+
|
123
141
|
except Exception as e:
|
124
142
|
self.print_error(f"Failed to generate certificates: {e}")
|
125
143
|
return False
|
126
|
-
|
144
|
+
|
127
145
|
def generate_configurations(self) -> bool:
|
128
146
|
"""Generate test configurations."""
|
129
147
|
self.print_step("4", "Configuration Generation")
|
130
|
-
|
148
|
+
|
131
149
|
try:
|
132
150
|
# Run configuration generation script
|
133
|
-
cmd = [
|
151
|
+
cmd = [
|
152
|
+
sys.executable,
|
153
|
+
"-m",
|
154
|
+
"mcp_proxy_adapter.examples.generate_test_configs",
|
155
|
+
]
|
134
156
|
self.print_info("Running configuration generation script...")
|
135
|
-
|
136
|
-
result = subprocess.run(
|
137
|
-
|
157
|
+
|
158
|
+
result = subprocess.run(
|
159
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
160
|
+
)
|
161
|
+
|
138
162
|
if result.returncode == 0:
|
139
163
|
self.print_success("Configurations generated successfully")
|
140
164
|
if result.stdout:
|
@@ -146,39 +170,52 @@ class FullTestSuiteRunner:
|
|
146
170
|
print("Error output:")
|
147
171
|
print(result.stderr)
|
148
172
|
return False
|
149
|
-
|
173
|
+
|
150
174
|
except Exception as e:
|
151
175
|
self.print_error(f"Failed to generate configurations: {e}")
|
152
176
|
return False
|
153
|
-
|
177
|
+
|
154
178
|
def run_security_tests(self) -> bool:
|
155
179
|
"""Run the security test suite."""
|
156
180
|
self.print_step("5", "Security Testing")
|
157
|
-
|
181
|
+
|
158
182
|
try:
|
159
183
|
# Run security tests
|
160
|
-
cmd = [
|
184
|
+
cmd = [
|
185
|
+
sys.executable,
|
186
|
+
"-m",
|
187
|
+
"mcp_proxy_adapter.examples.run_security_tests",
|
188
|
+
"--verbose",
|
189
|
+
]
|
161
190
|
self.print_info("Running security tests...")
|
162
|
-
|
191
|
+
|
163
192
|
# Debug: show current working directory and check files
|
164
193
|
self.print_info(f"DEBUG: Current working directory: {os.getcwd()}")
|
165
194
|
self.print_info(f"DEBUG: Working directory from class: {self.working_dir}")
|
166
|
-
|
195
|
+
|
167
196
|
# Check if certificates exist before running tests
|
168
197
|
localhost_cert = self.certs_dir / "localhost_server.crt"
|
169
|
-
self.print_info(
|
198
|
+
self.print_info(
|
199
|
+
f"DEBUG: localhost_server.crt exists: {localhost_cert.exists()}"
|
200
|
+
)
|
170
201
|
if localhost_cert.exists():
|
171
|
-
self.print_info(
|
202
|
+
self.print_info(
|
203
|
+
f"DEBUG: localhost_server.crt is symlink: {localhost_cert.is_symlink()}"
|
204
|
+
)
|
172
205
|
if localhost_cert.is_symlink():
|
173
|
-
self.print_info(
|
174
|
-
|
206
|
+
self.print_info(
|
207
|
+
f"DEBUG: localhost_server.crt symlink target: {localhost_cert.readlink()}"
|
208
|
+
)
|
209
|
+
|
175
210
|
# List all files in certs directory
|
176
211
|
self.print_info("DEBUG: Files in certs directory:")
|
177
212
|
for file in self.certs_dir.iterdir():
|
178
213
|
self.print_info(f"DEBUG: {file.name} -> {file}")
|
179
|
-
|
180
|
-
result = subprocess.run(
|
181
|
-
|
214
|
+
|
215
|
+
result = subprocess.run(
|
216
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
217
|
+
)
|
218
|
+
|
182
219
|
if result.returncode == 0:
|
183
220
|
self.print_success("Security tests completed successfully!")
|
184
221
|
if result.stdout:
|
@@ -193,87 +230,85 @@ class FullTestSuiteRunner:
|
|
193
230
|
print("Error output:")
|
194
231
|
print(result.stderr)
|
195
232
|
return False
|
196
|
-
|
233
|
+
|
197
234
|
except Exception as e:
|
198
235
|
self.print_error(f"Failed to run security tests: {e}")
|
199
236
|
return False
|
200
|
-
|
237
|
+
|
201
238
|
def cleanup(self):
|
202
239
|
"""Clean up temporary files and processes."""
|
203
240
|
self.print_info("Cleaning up...")
|
204
|
-
|
241
|
+
|
205
242
|
# Simple cleanup - just print success message
|
206
243
|
# Process cleanup is handled by the test scripts themselves
|
207
244
|
print("ā
Cleanup completed")
|
208
|
-
|
209
|
-
|
210
245
|
|
211
246
|
def cleanup_directories(self) -> bool:
|
212
247
|
"""Clean up existing test directories before starting."""
|
213
248
|
self.print_info("Cleaning up existing test directories...")
|
214
|
-
|
249
|
+
|
215
250
|
try:
|
216
251
|
import shutil
|
217
|
-
|
252
|
+
|
218
253
|
# Directories to clean
|
219
254
|
dirs_to_clean = [self.configs_dir, self.certs_dir, self.keys_dir]
|
220
255
|
files_to_clean = [self.working_dir / "roles.json"]
|
221
|
-
|
256
|
+
|
222
257
|
# Remove directories
|
223
258
|
for dir_path in dirs_to_clean:
|
224
259
|
if dir_path.exists():
|
225
260
|
shutil.rmtree(dir_path)
|
226
261
|
print(f"šļø Removed directory: {dir_path}")
|
227
|
-
|
262
|
+
|
228
263
|
# Remove files
|
229
264
|
for file_path in files_to_clean:
|
230
265
|
if file_path.exists():
|
231
266
|
file_path.unlink()
|
232
267
|
print(f"šļø Removed file: {file_path}")
|
233
|
-
|
268
|
+
|
234
269
|
self.print_success("Directory cleanup completed")
|
235
270
|
return True
|
236
|
-
|
271
|
+
|
237
272
|
except Exception as e:
|
238
273
|
self.print_error(f"Failed to cleanup directories: {e}")
|
239
274
|
return False
|
240
|
-
|
275
|
+
|
241
276
|
def run_full_suite(self) -> bool:
|
242
277
|
"""Run the complete test suite."""
|
243
278
|
print("š MCP Proxy Adapter - Full Test Suite")
|
244
279
|
print("=" * 60)
|
245
280
|
print(f"Working directory: {self.working_dir}")
|
246
281
|
print(f"Python executable: {sys.executable}")
|
247
|
-
|
282
|
+
|
248
283
|
try:
|
249
284
|
# Step 0: Clean up existing directories
|
250
285
|
if not self.cleanup_directories():
|
251
286
|
return False
|
252
|
-
|
287
|
+
|
253
288
|
# Step 1: Environment validation
|
254
289
|
if not self.check_environment():
|
255
290
|
return False
|
256
|
-
|
291
|
+
|
257
292
|
# Step 2: Directory creation
|
258
293
|
if not self.create_directories():
|
259
294
|
return False
|
260
|
-
|
295
|
+
|
261
296
|
# Step 3: Certificate generation
|
262
297
|
if not self.generate_certificates():
|
263
298
|
return False
|
264
|
-
|
299
|
+
|
265
300
|
# Step 4: Configuration generation
|
266
301
|
if not self.generate_configurations():
|
267
302
|
return False
|
268
|
-
|
303
|
+
|
269
304
|
# Step 5: Security testing
|
270
305
|
if not self.run_security_tests():
|
271
306
|
return False
|
272
|
-
|
307
|
+
|
273
308
|
# All steps completed successfully
|
274
309
|
print(f"\n{'='*60}")
|
275
310
|
print("š FULL TEST SUITE COMPLETED SUCCESSFULLY!")
|
276
|
-
print("="*60)
|
311
|
+
print("=" * 60)
|
277
312
|
print("ā
Environment validated")
|
278
313
|
print("ā
Directories cleaned")
|
279
314
|
print("ā
Directories created")
|
@@ -284,9 +319,9 @@ class FullTestSuiteRunner:
|
|
284
319
|
print(f"š Configurations: {self.configs_dir}")
|
285
320
|
print(f"š Certificates: {self.certs_dir}")
|
286
321
|
print(f"š Keys: {self.keys_dir}")
|
287
|
-
|
322
|
+
|
288
323
|
return True
|
289
|
-
|
324
|
+
|
290
325
|
except KeyboardInterrupt:
|
291
326
|
print("\n\nā ļø Test suite interrupted by user")
|
292
327
|
return False
|
@@ -301,12 +336,14 @@ class FullTestSuiteRunner:
|
|
301
336
|
except Exception as e:
|
302
337
|
self.print_error(f"Cleanup failed in finally block: {e}")
|
303
338
|
import traceback
|
339
|
+
|
304
340
|
traceback.print_exc()
|
305
341
|
|
342
|
+
|
306
343
|
def main():
|
307
344
|
"""Main entry point."""
|
308
345
|
runner = FullTestSuiteRunner()
|
309
|
-
|
346
|
+
|
310
347
|
try:
|
311
348
|
success = runner.run_full_suite()
|
312
349
|
sys.exit(0 if success else 1)
|
@@ -314,5 +351,6 @@ def main():
|
|
314
351
|
print(f"ā Fatal error: {e}")
|
315
352
|
sys.exit(1)
|
316
353
|
|
354
|
+
|
317
355
|
if __name__ == "__main__":
|
318
356
|
main()
|
@@ -52,7 +52,7 @@ class ProxyRouter:
|
|
52
52
|
"metadata": registration.metadata,
|
53
53
|
"registered_at": datetime.now().isoformat(),
|
54
54
|
"last_heartbeat": datetime.now().isoformat(),
|
55
|
-
"status": "active"
|
55
|
+
"status": "active",
|
56
56
|
}
|
57
57
|
print(f"ā
Registered adapter: {adapter_id} at {registration.url}")
|
58
58
|
return {"status": "registered", "adapter_id": adapter_id}
|
@@ -72,7 +72,7 @@ class ProxyRouter:
|
|
72
72
|
"""List all registered adapters."""
|
73
73
|
return {
|
74
74
|
"adapters": list(registered_adapters.values()),
|
75
|
-
"count": len(registered_adapters)
|
75
|
+
"count": len(registered_adapters),
|
76
76
|
}
|
77
77
|
|
78
78
|
@self.app.get("/proxy/health")
|
@@ -81,14 +81,16 @@ class ProxyRouter:
|
|
81
81
|
return {
|
82
82
|
"status": "healthy",
|
83
83
|
"timestamp": datetime.now().isoformat(),
|
84
|
-
"adapters_count": len(registered_adapters)
|
84
|
+
"adapters_count": len(registered_adapters),
|
85
85
|
}
|
86
86
|
|
87
87
|
@self.app.post("/proxy/heartbeat")
|
88
88
|
async def heartbeat(adapter_id: str):
|
89
89
|
"""Receive heartbeat from adapter."""
|
90
90
|
if adapter_id in registered_adapters:
|
91
|
-
registered_adapters[adapter_id][
|
91
|
+
registered_adapters[adapter_id][
|
92
|
+
"last_heartbeat"
|
93
|
+
] = datetime.now().isoformat()
|
92
94
|
return {"status": "ok", "adapter_id": adapter_id}
|
93
95
|
else:
|
94
96
|
raise HTTPException(status_code=404, detail="Adapter not found")
|
@@ -101,10 +103,21 @@ def create_proxy_app() -> FastAPI:
|
|
101
103
|
|
102
104
|
|
103
105
|
def main() -> None:
|
104
|
-
parser = argparse.ArgumentParser(
|
105
|
-
|
106
|
-
|
107
|
-
parser.add_argument(
|
106
|
+
parser = argparse.ArgumentParser(
|
107
|
+
description="Run local proxy server for MCP examples"
|
108
|
+
)
|
109
|
+
parser.add_argument(
|
110
|
+
"--host", default="127.0.0.1", help="Host to bind to (default: 127.0.0.1)"
|
111
|
+
)
|
112
|
+
parser.add_argument(
|
113
|
+
"--port", type=int, default=3004, help="Port to bind to (default: 3004)"
|
114
|
+
)
|
115
|
+
parser.add_argument(
|
116
|
+
"--log-level",
|
117
|
+
default="info",
|
118
|
+
choices=["debug", "info", "warning", "error"],
|
119
|
+
help="Log level",
|
120
|
+
)
|
108
121
|
|
109
122
|
args = parser.parse_args()
|
110
123
|
|
@@ -143,4 +156,4 @@ def main() -> None:
|
|
143
156
|
|
144
157
|
|
145
158
|
if __name__ == "__main__":
|
146
|
-
main()
|
159
|
+
main()
|