mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -6,6 +6,7 @@ and connection types supported by the security framework.
6
6
  Author: Vasiliy Zdanovskiy
7
7
  email: vasilyvz@gmail.com
8
8
  """
9
+
9
10
  import asyncio
10
11
  import json
11
12
  import os
@@ -17,16 +18,35 @@ from pathlib import Path
17
18
  import aiohttp
18
19
  import requests
19
20
  from requests.exceptions import RequestException
21
+
20
22
  # Import security framework components
21
23
  try:
22
- from mcp_security_framework import SecurityManager, AuthManager, CertificateManager, PermissionManager
23
- from mcp_security_framework.utils import generate_api_key, create_jwt_token, validate_jwt_token
24
- from mcp_security_framework.utils import extract_roles_from_cert, validate_certificate_chain
25
- from mcp_security_framework.utils import create_ssl_context, validate_server_certificate
24
+ from mcp_security_framework import (
25
+ SecurityManager,
26
+ AuthManager,
27
+ CertificateManager,
28
+ PermissionManager,
29
+ )
30
+ from mcp_security_framework.utils import (
31
+ generate_api_key,
32
+ create_jwt_token,
33
+ validate_jwt_token,
34
+ )
35
+ from mcp_security_framework.utils import (
36
+ extract_roles_from_cert,
37
+ validate_certificate_chain,
38
+ )
39
+ from mcp_security_framework.utils import (
40
+ create_ssl_context,
41
+ validate_server_certificate,
42
+ )
43
+
26
44
  SECURITY_FRAMEWORK_AVAILABLE = True
27
45
  except ImportError:
28
46
  SECURITY_FRAMEWORK_AVAILABLE = False
29
47
  print("Warning: mcp_security_framework not available. Using basic HTTP client.")
48
+
49
+
30
50
  class UniversalClient:
31
51
  """
32
52
  Universal client that demonstrates all possible secure connection methods.
@@ -39,6 +59,7 @@ class UniversalClient:
39
59
  - Role-based access control
40
60
  - Rate limiting awareness
41
61
  """
62
+
42
63
  def __init__(self, config: Dict[str, Any]):
43
64
  """
44
65
  Initialize universal client with configuration.
@@ -64,6 +85,7 @@ class UniversalClient:
64
85
  self.current_token: Optional[str] = None
65
86
  self.token_expiry: Optional[float] = None
66
87
  print(f"Universal client initialized with auth method: {self.auth_method}")
88
+
67
89
  def _initialize_security_managers(self) -> None:
68
90
  """Initialize security framework managers."""
69
91
  try:
@@ -81,16 +103,21 @@ class UniversalClient:
81
103
  print("Security framework managers initialized successfully")
82
104
  except Exception as e:
83
105
  print(f"Warning: Failed to initialize security managers: {e}")
106
+
84
107
  async def __aenter__(self):
85
108
  """Async context manager entry."""
86
109
  await self.connect()
87
110
  return self
111
+
88
112
  async def __aexit__(self, exc_type, exc_val, exc_tb):
89
113
  """Async context manager exit."""
90
114
  await self.disconnect()
115
+
91
116
  async def connect(self) -> None:
92
117
  """Establish connection with authentication."""
93
- print(f"Connecting to {self.base_url} with {self.auth_method} authentication...")
118
+ print(
119
+ f"Connecting to {self.base_url} with {self.auth_method} authentication..."
120
+ )
94
121
  # Create SSL context
95
122
  ssl_context = self._create_ssl_context()
96
123
  # Create connector with SSL context
@@ -111,12 +138,14 @@ class UniversalClient:
111
138
  else:
112
139
  print("No authentication required")
113
140
  print("Connection established successfully")
141
+
114
142
  async def disconnect(self) -> None:
115
143
  """Close connection and cleanup."""
116
144
  if self.session:
117
145
  await self.session.close()
118
146
  self.session = None
119
147
  print("Connection closed")
148
+
120
149
  async def _authenticate_api_key(self) -> None:
121
150
  """Authenticate using API key."""
122
151
  api_key_config = self.security_config.get("api_key", {})
@@ -126,6 +155,7 @@ class UniversalClient:
126
155
  # Store API key for requests
127
156
  self.current_token = api_key
128
157
  print(f"Authenticated with API key: {api_key[:8]}...")
158
+
129
159
  async def _authenticate_jwt(self) -> None:
130
160
  """Authenticate using JWT token."""
131
161
  jwt_config = self.security_config.get("jwt", {})
@@ -142,20 +172,20 @@ class UniversalClient:
142
172
  # Create JWT token
143
173
  if SECURITY_FRAMEWORK_AVAILABLE:
144
174
  self.current_token = create_jwt_token(
145
- username,
146
- secret,
147
- expiry_hours=jwt_config.get("expiry_hours", 24)
175
+ username, secret, expiry_hours=jwt_config.get("expiry_hours", 24)
148
176
  )
149
177
  else:
150
178
  # Simple JWT creation (for demonstration)
151
179
  import jwt
180
+
152
181
  payload = {
153
182
  "username": username,
154
- "exp": time.time() + (jwt_config.get("expiry_hours", 24) * 3600)
183
+ "exp": time.time() + (jwt_config.get("expiry_hours", 24) * 3600),
155
184
  }
156
185
  self.current_token = jwt.encode(payload, secret, algorithm="HS256")
157
186
  self.token_expiry = time.time() + (jwt_config.get("expiry_hours", 24) * 3600)
158
187
  print(f"Authenticated with JWT token: {self.current_token[:20]}...")
188
+
159
189
  async def _authenticate_certificate(self) -> None:
160
190
  """Authenticate using client certificate."""
161
191
  cert_config = self.security_config.get("certificate", {})
@@ -175,6 +205,7 @@ class UniversalClient:
175
205
  except Exception as e:
176
206
  print(f"Warning: Certificate validation failed: {e}")
177
207
  print("Certificate authentication prepared")
208
+
178
209
  async def _authenticate_basic(self) -> None:
179
210
  """Authenticate using basic authentication."""
180
211
  basic_config = self.security_config.get("basic", {})
@@ -183,9 +214,11 @@ class UniversalClient:
183
214
  if not username or not password:
184
215
  raise ValueError("Basic auth credentials not provided in configuration")
185
216
  import base64
217
+
186
218
  credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
187
219
  self.current_token = f"Basic {credentials}"
188
220
  print(f"Authenticated with basic auth: {username}")
221
+
189
222
  def _get_auth_headers(self) -> Dict[str, str]:
190
223
  """Get authentication headers for requests."""
191
224
  headers = {"Content-Type": "application/json"}
@@ -200,6 +233,7 @@ class UniversalClient:
200
233
  elif self.auth_method == "basic":
201
234
  headers["Authorization"] = self.current_token
202
235
  return headers
236
+
203
237
  def _create_ssl_context(self) -> Optional[ssl.SSLContext]:
204
238
  """Create SSL context for secure connections."""
205
239
  ssl_config = self.security_config.get("ssl", {})
@@ -236,12 +270,13 @@ class UniversalClient:
236
270
  except Exception as e:
237
271
  print(f"Warning: Failed to create SSL context: {e}")
238
272
  return None
273
+
239
274
  async def request(
240
275
  self,
241
276
  method: str,
242
277
  endpoint: str,
243
278
  data: Optional[Dict[str, Any]] = None,
244
- headers: Optional[Dict[str, str]] = None
279
+ headers: Optional[Dict[str, str]] = None,
245
280
  ) -> Dict[str, Any]:
246
281
  """
247
282
  Make authenticated request to server.
@@ -266,14 +301,18 @@ class UniversalClient:
266
301
  url,
267
302
  json=data,
268
303
  headers=request_headers,
269
- timeout=aiohttp.ClientTimeout(total=self.timeout)
304
+ timeout=aiohttp.ClientTimeout(total=self.timeout),
270
305
  ) as response:
271
306
  result = await response.json()
272
307
  # Validate response if security framework available
273
308
  if SECURITY_FRAMEWORK_AVAILABLE and self.security_manager:
274
- self.security_manager.validate_server_response(dict(response.headers))
309
+ self.security_manager.validate_server_response(
310
+ dict(response.headers)
311
+ )
275
312
  if response.status >= 400:
276
- print(f"Request failed with status {response.status}: {result}")
313
+ print(
314
+ f"Request failed with status {response.status}: {result}"
315
+ )
277
316
  return {"error": result, "status": response.status}
278
317
  return result
279
318
  except Exception as e:
@@ -285,18 +324,27 @@ class UniversalClient:
285
324
  except Exception as e:
286
325
  print(f"Request failed: {e}")
287
326
  raise
327
+
288
328
  async def get(self, endpoint: str, **kwargs) -> Dict[str, Any]:
289
329
  """Make GET request."""
290
330
  return await self.request("GET", endpoint, **kwargs)
291
- async def post(self, endpoint: str, data: Dict[str, Any], **kwargs) -> Dict[str, Any]:
331
+
332
+ async def post(
333
+ self, endpoint: str, data: Dict[str, Any], **kwargs
334
+ ) -> Dict[str, Any]:
292
335
  """Make POST request."""
293
336
  return await self.request("POST", endpoint, data=data, **kwargs)
294
- async def put(self, endpoint: str, data: Dict[str, Any], **kwargs) -> Dict[str, Any]:
337
+
338
+ async def put(
339
+ self, endpoint: str, data: Dict[str, Any], **kwargs
340
+ ) -> Dict[str, Any]:
295
341
  """Make PUT request."""
296
342
  return await self.request("PUT", endpoint, data=data, **kwargs)
343
+
297
344
  async def delete(self, endpoint: str, **kwargs) -> Dict[str, Any]:
298
345
  """Make DELETE request."""
299
346
  return await self.request("DELETE", endpoint, **kwargs)
347
+
300
348
  async def test_connection(self) -> bool:
301
349
  """Test connection to server."""
302
350
  try:
@@ -310,6 +358,7 @@ class UniversalClient:
310
358
  except Exception as e:
311
359
  print(f"āŒ Connection test failed: {e}")
312
360
  return False
361
+
313
362
  async def test_security_features(self) -> Dict[str, bool]:
314
363
  """Test various security features."""
315
364
  results = {}
@@ -333,10 +382,10 @@ class UniversalClient:
333
382
  else:
334
383
  results["certificate_validation"] = False
335
384
  return results
385
+
386
+
336
387
  def create_client_config(
337
- server_url: str,
338
- auth_method: str = "none",
339
- **kwargs
388
+ server_url: str, auth_method: str = "none", **kwargs
340
389
  ) -> Dict[str, Any]:
341
390
  """
342
391
  Create client configuration for different authentication methods.
@@ -352,40 +401,40 @@ def create_client_config(
352
401
  "timeout": 30,
353
402
  "retry_attempts": 3,
354
403
  "retry_delay": 1,
355
- "security": {
356
- "auth_method": auth_method
357
- }
404
+ "security": {"auth_method": auth_method},
358
405
  }
359
406
  if auth_method == "api_key":
360
407
  config["security"]["api_key"] = {
361
408
  "key": kwargs.get("api_key", "your_api_key_here"),
362
- "header": kwargs.get("header", "X-API-Key")
409
+ "header": kwargs.get("header", "X-API-Key"),
363
410
  }
364
411
  elif auth_method == "jwt":
365
412
  config["security"]["jwt"] = {
366
413
  "username": kwargs.get("username", "user"),
367
414
  "password": kwargs.get("password", "password"),
368
415
  "secret": kwargs.get("secret", "your_jwt_secret"),
369
- "expiry_hours": kwargs.get("expiry_hours", 24)
416
+ "expiry_hours": kwargs.get("expiry_hours", 24),
370
417
  }
371
418
  elif auth_method == "certificate":
372
419
  config["security"]["certificate"] = {
373
420
  "enabled": True,
374
421
  "cert_file": kwargs.get("cert_file", "./certs/client.crt"),
375
422
  "key_file": kwargs.get("key_file", "./keys/client.key"),
376
- "ca_cert_file": kwargs.get("ca_cert_file", "./certs/ca.crt")
423
+ "ca_cert_file": kwargs.get("ca_cert_file", "./certs/ca.crt"),
377
424
  }
378
425
  config["security"]["ssl"] = {
379
426
  "enabled": True,
380
427
  "check_hostname": kwargs.get("check_hostname", True),
381
- "ca_cert_file": kwargs.get("ca_cert_file", "./certs/ca.crt")
428
+ "ca_cert_file": kwargs.get("ca_cert_file", "./certs/ca.crt"),
382
429
  }
383
430
  elif auth_method == "basic":
384
431
  config["security"]["basic"] = {
385
432
  "username": kwargs.get("username", "user"),
386
- "password": kwargs.get("password", "password")
433
+ "password": kwargs.get("password", "password"),
387
434
  }
388
435
  return config
436
+
437
+
389
438
  async def demo_all_connection_methods():
390
439
  """Demonstrate all possible connection methods."""
391
440
  print("šŸš€ Universal Client Demo - All Connection Methods")
@@ -394,15 +443,13 @@ async def demo_all_connection_methods():
394
443
  test_configs = [
395
444
  {
396
445
  "name": "No Authentication",
397
- "config": create_client_config("http://localhost:8000", "none")
446
+ "config": create_client_config("http://localhost:8000", "none"),
398
447
  },
399
448
  {
400
449
  "name": "API Key Authentication",
401
450
  "config": create_client_config(
402
- "http://localhost:8000",
403
- "api_key",
404
- api_key="demo_api_key_123"
405
- )
451
+ "http://localhost:8000", "api_key", api_key="demo_api_key_123"
452
+ ),
406
453
  },
407
454
  {
408
455
  "name": "JWT Authentication",
@@ -411,8 +458,8 @@ async def demo_all_connection_methods():
411
458
  "jwt",
412
459
  username="demo_user",
413
460
  password="demo_password",
414
- secret="demo_jwt_secret"
415
- )
461
+ secret="demo_jwt_secret",
462
+ ),
416
463
  },
417
464
  {
418
465
  "name": "Basic Authentication",
@@ -420,8 +467,8 @@ async def demo_all_connection_methods():
420
467
  "http://localhost:8000",
421
468
  "basic",
422
469
  username="demo_user",
423
- password="demo_password"
424
- )
470
+ password="demo_password",
471
+ ),
425
472
  },
426
473
  {
427
474
  "name": "Certificate Authentication (HTTPS)",
@@ -430,9 +477,9 @@ async def demo_all_connection_methods():
430
477
  "certificate",
431
478
  cert_file="./certs/client.crt",
432
479
  key_file="./keys/client.key",
433
- ca_cert_file="./certs/ca.crt"
434
- )
435
- }
480
+ ca_cert_file="./certs/ca.crt",
481
+ ),
482
+ },
436
483
  ]
437
484
  for test_config in test_configs:
438
485
  print(f"\nšŸ“‹ Testing: {test_config['name']}")
@@ -459,6 +506,8 @@ async def demo_all_connection_methods():
459
506
  except Exception as e:
460
507
  print(f"āŒ Test failed: {e}")
461
508
  print("\nšŸŽ‰ Demo completed!")
509
+
510
+
462
511
  async def demo_specific_connection(auth_method: str, **kwargs):
463
512
  """
464
513
  Demo specific connection method.
@@ -484,7 +533,7 @@ async def demo_specific_connection(auth_method: str, **kwargs):
484
533
  "jsonrpc": "2.0",
485
534
  "method": "test_command",
486
535
  "params": {"message": "Hello from universal client!"},
487
- "id": 1
536
+ "id": 1,
488
537
  }
489
538
  result = await client.post("/api/jsonrpc", command_data)
490
539
  print(f"Command Result: {result}")
@@ -492,11 +541,16 @@ async def demo_specific_connection(auth_method: str, **kwargs):
492
541
  print(f"API calls failed: {e}")
493
542
  else:
494
543
  print("āŒ Connection failed")
544
+
545
+
495
546
  if __name__ == "__main__":
496
547
  import sys
497
548
  import argparse
498
549
  import json
499
- parser = argparse.ArgumentParser(description="Universal Client for MCP Proxy Adapter")
550
+
551
+ parser = argparse.ArgumentParser(
552
+ description="Universal Client for MCP Proxy Adapter"
553
+ )
500
554
  parser.add_argument("--config", help="Path to configuration file")
501
555
  parser.add_argument("--method", help="JSON-RPC method to call")
502
556
  parser.add_argument("--params", help="JSON-RPC parameters (JSON string)")
@@ -506,7 +560,7 @@ if __name__ == "__main__":
506
560
  if args.config:
507
561
  # Load configuration from file
508
562
  try:
509
- with open(args.config, 'r') as f:
563
+ with open(args.config, "r") as f:
510
564
  config_data = json.load(f)
511
565
  # Extract server configuration
512
566
  server_config = config_data.get("server", {})
@@ -527,21 +581,20 @@ if __name__ == "__main__":
527
581
  "timeout": 30,
528
582
  "retry_attempts": 3,
529
583
  "retry_delay": 1,
530
- "security": {
531
- "auth_method": "none"
532
- }
584
+ "security": {"auth_method": "none"},
533
585
  }
534
586
  # Add SSL configuration if needed
535
587
  if ssl_enabled:
536
588
  client_config["security"]["ssl"] = {
537
589
  "enabled": True,
538
590
  "check_hostname": False,
539
- "verify": False
591
+ "verify": False,
540
592
  }
541
593
  # Add CA certificate if available
542
594
  ca_cert = ssl_config.get("ca_cert")
543
595
  if ca_cert and os.path.exists(ca_cert):
544
596
  client_config["security"]["ssl"]["ca_cert_file"] = ca_cert
597
+
545
598
  async def test_config_connection():
546
599
  async with UniversalClient(client_config) as client:
547
600
  # Test connection
@@ -562,11 +615,13 @@ if __name__ == "__main__":
562
615
  "jsonrpc": "2.0",
563
616
  "method": args.method,
564
617
  "params": params,
565
- "id": 1
618
+ "id": 1,
566
619
  }
567
620
  try:
568
621
  result = await client.post("/api/jsonrpc", command_data)
569
- print(f"āœ… Method '{args.method}' executed successfully:")
622
+ print(
623
+ f"āœ… Method '{args.method}' executed successfully:"
624
+ )
570
625
  print(json.dumps(result, indent=2))
571
626
  except Exception as e:
572
627
  print(f"āŒ Method execution failed: {e}")
@@ -576,7 +631,7 @@ if __name__ == "__main__":
576
631
  "jsonrpc": "2.0",
577
632
  "method": "help",
578
633
  "params": {},
579
- "id": 1
634
+ "id": 1,
580
635
  }
581
636
  try:
582
637
  result = await client.post("/api/jsonrpc", command_data)
@@ -587,6 +642,7 @@ if __name__ == "__main__":
587
642
  else:
588
643
  print("āŒ Connection failed")
589
644
  print("Connection closed")
645
+
590
646
  asyncio.run(test_config_connection())
591
647
  except FileNotFoundError:
592
648
  print(f"āŒ Configuration file not found: {args.config}")
@@ -601,22 +657,23 @@ if __name__ == "__main__":
601
657
  if auth_method == "api_key":
602
658
  kwargs["api_key"] = "demo_key_123"
603
659
  elif auth_method == "jwt":
604
- kwargs.update({
605
- "username": "demo_user",
606
- "password": "demo_password",
607
- "secret": "demo_secret"
608
- })
660
+ kwargs.update(
661
+ {
662
+ "username": "demo_user",
663
+ "password": "demo_password",
664
+ "secret": "demo_secret",
665
+ }
666
+ )
609
667
  elif auth_method == "certificate":
610
- kwargs.update({
611
- "cert_file": "./certs/client.crt",
612
- "key_file": "./keys/client.key",
613
- "ca_cert_file": "./certs/ca.crt"
614
- })
668
+ kwargs.update(
669
+ {
670
+ "cert_file": "./certs/client.crt",
671
+ "key_file": "./keys/client.key",
672
+ "ca_cert_file": "./certs/ca.crt",
673
+ }
674
+ )
615
675
  elif auth_method == "basic":
616
- kwargs.update({
617
- "username": "demo_user",
618
- "password": "demo_password"
619
- })
676
+ kwargs.update({"username": "demo_user", "password": "demo_password"})
620
677
  asyncio.run(demo_specific_connection(auth_method, **kwargs))
621
678
  else:
622
679
  # Demo all connection methods