mcp-proxy-adapter 6.2.24__py3-none-any.whl → 6.2.26__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 (33) hide show
  1. mcp_proxy_adapter/api/app.py +0 -3
  2. mcp_proxy_adapter/api/middleware/protocol_middleware.py +10 -10
  3. mcp_proxy_adapter/commands/health_command.py +1 -1
  4. mcp_proxy_adapter/config.py +234 -23
  5. mcp_proxy_adapter/core/protocol_manager.py +9 -9
  6. mcp_proxy_adapter/examples/create_certificates_simple.py +7 -17
  7. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  8. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  9. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  10. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  11. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  12. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  13. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  14. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  15. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  16. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  17. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  18. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  19. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  20. mcp_proxy_adapter/examples/generate_test_configs.py +70 -33
  21. mcp_proxy_adapter/examples/run_full_test_suite.py +302 -109
  22. mcp_proxy_adapter/examples/run_security_tests.py +14 -5
  23. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  24. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  25. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  26. mcp_proxy_adapter/main.py +0 -2
  27. mcp_proxy_adapter/utils/config_generator.py +275 -7
  28. {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/METADATA +1 -1
  29. {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/RECORD +33 -17
  30. {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/WHEEL +0 -0
  31. {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/entry_points.txt +0 -0
  32. {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/licenses/LICENSE +0 -0
  33. {mcp_proxy_adapter-6.2.24.dist-info → mcp_proxy_adapter-6.2.26.dist-info}/top_level.txt +0 -0
@@ -350,9 +350,6 @@ def create_app(title: Optional[str] = None, description: Optional[str] = None, v
350
350
  )
351
351
 
352
352
  # Setup middleware using the new middleware package
353
- print(f"DEBUG create_app: calling setup_middleware with config type: {type(current_config)}")
354
- if hasattr(current_config, 'keys'):
355
- print(f"DEBUG create_app: current_config keys: {list(current_config.keys())}")
356
353
  setup_middleware(app, current_config)
357
354
 
358
355
  # Use custom OpenAPI schema
@@ -87,7 +87,7 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
87
87
  Returns:
88
88
  Response object
89
89
  """
90
- logger.info(f"ProtocolMiddleware.dispatch called for {request.method} {request.url.path}")
90
+ logger.debug(f"ProtocolMiddleware.dispatch called for {request.method} {request.url.path}")
91
91
  try:
92
92
  # Get protocol from request
93
93
  protocol = self._get_request_protocol(request)
@@ -169,32 +169,32 @@ def setup_protocol_middleware(app, app_config: Optional[Dict[str, Any]] = None):
169
169
  app: FastAPI application
170
170
  app_config: Application configuration dictionary (optional)
171
171
  """
172
- logger.info(f"setup_protocol_middleware - app_config type: {type(app_config)}")
172
+ logger.debug(f"setup_protocol_middleware - app_config type: {type(app_config)}")
173
173
 
174
174
  # Check if protocol management is enabled
175
175
  if app_config is None:
176
176
  from mcp_proxy_adapter.config import config
177
177
  app_config = config.get_all()
178
- logger.info(f"setup_protocol_middleware - loaded from global config, type: {type(app_config)}")
178
+ logger.debug(f"setup_protocol_middleware - loaded from global config, type: {type(app_config)}")
179
179
 
180
- logger.info(f"setup_protocol_middleware - final app_config type: {type(app_config)}")
180
+ logger.debug(f"setup_protocol_middleware - final app_config type: {type(app_config)}")
181
181
 
182
182
  if hasattr(app_config, 'get'):
183
- logger.info(f"setup_protocol_middleware - app_config keys: {list(app_config.keys()) if hasattr(app_config, 'keys') else 'no keys'}")
183
+ logger.debug(f"setup_protocol_middleware - app_config keys: {list(app_config.keys()) if hasattr(app_config, 'keys') else 'no keys'}")
184
184
  protocols_config = app_config.get("protocols", {})
185
- logger.info(f"setup_protocol_middleware - protocols_config type: {type(protocols_config)}")
185
+ logger.debug(f"setup_protocol_middleware - protocols_config type: {type(protocols_config)}")
186
186
  enabled = protocols_config.get("enabled", True) if hasattr(protocols_config, 'get') else True
187
187
  else:
188
- logger.info(f"setup_protocol_middleware - app_config is not dict-like: {repr(app_config)}")
188
+ logger.debug(f"setup_protocol_middleware - app_config is not dict-like: {repr(app_config)}")
189
189
  enabled = True
190
190
 
191
- logger.info(f"setup_protocol_middleware - protocol management enabled: {enabled}")
191
+ logger.debug(f"setup_protocol_middleware - protocol management enabled: {enabled}")
192
192
 
193
193
  if enabled:
194
194
  # Create protocol middleware with current configuration
195
- logger.info(f"setup_protocol_middleware - creating ProtocolMiddleware with config type: {type(app_config)}")
195
+ logger.debug(f"setup_protocol_middleware - creating ProtocolMiddleware with config type: {type(app_config)}")
196
196
  middleware = ProtocolMiddleware(app, app_config)
197
- logger.info(f"setup_protocol_middleware - adding middleware to app")
197
+ logger.debug(f"setup_protocol_middleware - adding middleware to app")
198
198
  app.add_middleware(ProtocolMiddleware, app_config=app_config)
199
199
  logger.info("Protocol middleware added to application")
200
200
  else:
@@ -80,7 +80,7 @@ class HealthCommand(Command):
80
80
  name = "health"
81
81
  result_class = HealthResult
82
82
 
83
- async def execute(self) -> HealthResult:
83
+ async def execute(self, **kwargs) -> HealthResult:
84
84
  """
85
85
  Execute health command.
86
86
 
@@ -7,14 +7,14 @@ email: vasilyvz@gmail.com
7
7
 
8
8
  import json
9
9
  import os
10
- from pathlib import Path
11
- from typing import Any, Dict, Optional
10
+ from typing import Any, Dict, Optional, List
12
11
 
13
12
 
14
13
  class Config:
15
14
  """
16
15
  Configuration management class for the microservice.
17
16
  Allows loading settings from configuration file and environment variables.
17
+ Supports optional features that can be enabled/disabled.
18
18
  """
19
19
 
20
20
  def __init__(self, config_path: Optional[str] = None):
@@ -22,7 +22,8 @@ class Config:
22
22
  Initialize configuration.
23
23
 
24
24
  Args:
25
- config_path: Path to configuration file. If not specified, "./config.json" is used.
25
+ config_path: Path to configuration file. If not specified,
26
+ "./config.json" is used.
26
27
  """
27
28
  self.config_path = config_path or "./config.json"
28
29
  self.config_data: Dict[str, Any] = {}
@@ -56,10 +57,13 @@ class Config:
56
57
  },
57
58
  "commands": {
58
59
  "auto_discovery": True,
59
- "commands_directory": "./commands", # Path to directory with command files
60
- "catalog_directory": "./catalog", # Path to command catalog directory
61
- "plugin_servers": [], # List of plugin server URLs
62
- "auto_install_dependencies": True # Automatically install plugin dependencies
60
+ "commands_directory": "./commands",
61
+ "catalog_directory": "./catalog",
62
+ "plugin_servers": [],
63
+ "auto_install_dependencies": True,
64
+ "enabled_commands": ["health", "echo", "list", "help"],
65
+ "disabled_commands": [],
66
+ "custom_commands_path": "./commands"
63
67
  },
64
68
  "ssl": {
65
69
  "enabled": False,
@@ -69,7 +73,10 @@ class Config:
69
73
  "ca_cert": None,
70
74
  "verify_client": False,
71
75
  "client_cert_required": False,
72
- "cipher_suites": ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"],
76
+ "cipher_suites": [
77
+ "TLS_AES_256_GCM_SHA384",
78
+ "TLS_CHACHA20_POLY1305_SHA256"
79
+ ],
73
80
  "min_tls_version": "TLSv1.2",
74
81
  "max_tls_version": "1.3",
75
82
  "token_auth": {
@@ -118,12 +125,6 @@ class Config:
118
125
  "auto_register_on_startup": True,
119
126
  "auto_unregister_on_shutdown": True
120
127
  },
121
- "commands": {
122
- "auto_discovery": True,
123
- "enabled_commands": ["health", "echo", "list", "help"],
124
- "disabled_commands": [],
125
- "custom_commands_path": "./commands"
126
- },
127
128
  "debug": {
128
129
  "enabled": False,
129
130
  "level": "WARNING"
@@ -226,7 +227,7 @@ class Config:
226
227
  "auto_discovery": True
227
228
  }
228
229
  }
229
-
230
+
230
231
  # Try to load configuration from file
231
232
  if os.path.exists(self.config_path):
232
233
  try:
@@ -235,7 +236,7 @@ class Config:
235
236
  self._update_nested_dict(self.config_data, file_config)
236
237
  except Exception as e:
237
238
  print(f"Error loading config from {self.config_path}: {e}")
238
-
239
+
239
240
  # Load configuration from environment variables
240
241
  self._load_env_variables()
241
242
 
@@ -300,14 +301,14 @@ class Config:
300
301
  Configuration value
301
302
  """
302
303
  parts = key.split(".")
303
-
304
+
304
305
  # Get value from config
305
306
  value = self.config_data
306
307
  for part in parts:
307
308
  if not isinstance(value, dict) or part not in value:
308
309
  return default
309
310
  value = value[part]
310
-
311
+
311
312
  return value
312
313
 
313
314
  def get_all(self) -> Dict[str, Any]:
@@ -332,17 +333,17 @@ class Config:
332
333
  self.config_data[key] = value
333
334
  else:
334
335
  section = parts[0]
335
- param = ".".join(parts[1:])
336
-
336
+ param_key = ".".join(parts[1:])
337
+
337
338
  if section not in self.config_data:
338
339
  self.config_data[section] = {}
339
-
340
+
340
341
  current = self.config_data[section]
341
342
  for part in parts[1:-1]:
342
343
  if part not in current:
343
344
  current[part] = {}
344
345
  current = current[part]
345
-
346
+
346
347
  current[parts[-1]] = value
347
348
 
348
349
  def save(self, path: Optional[str] = None) -> None:
@@ -350,7 +351,8 @@ class Config:
350
351
  Save configuration to file.
351
352
 
352
353
  Args:
353
- path: Path to configuration file. If not specified, self.config_path is used.
354
+ path: Path to configuration file. If not specified,
355
+ self.config_path is used.
354
356
  """
355
357
  save_path = path or self.config_path
356
358
  with open(save_path, 'w', encoding='utf-8') as f:
@@ -374,6 +376,215 @@ class Config:
374
376
  d[k] = v
375
377
  return d
376
378
 
379
+ def enable_feature(self, feature: str) -> None:
380
+ """
381
+ Enable a specific feature in the configuration.
382
+
383
+ Args:
384
+ feature: Feature to enable (ssl, auth, roles, proxy_registration,
385
+ security)
386
+ """
387
+ if feature == "ssl":
388
+ self.set("ssl.enabled", True)
389
+ self.set("security.ssl.enabled", True)
390
+ elif feature == "auth":
391
+ self.set("security.auth.enabled", True)
392
+ elif feature == "roles":
393
+ self.set("security.permissions.enabled", True)
394
+ self.set("roles.enabled", True)
395
+ elif feature == "proxy_registration":
396
+ self.set("proxy_registration.enabled", True)
397
+ elif feature == "security":
398
+ self.set("security.enabled", True)
399
+ elif feature == "rate_limit":
400
+ self.set("security.rate_limit.enabled", True)
401
+ elif feature == "certificates":
402
+ self.set("security.certificates.enabled", True)
403
+ else:
404
+ raise ValueError(f"Unknown feature: {feature}")
405
+
406
+ def disable_feature(self, feature: str) -> None:
407
+ """
408
+ Disable a specific feature in the configuration.
409
+
410
+ Args:
411
+ feature: Feature to disable (ssl, auth, roles, proxy_registration,
412
+ security)
413
+ """
414
+ if feature == "ssl":
415
+ self.set("ssl.enabled", False)
416
+ self.set("security.ssl.enabled", False)
417
+ elif feature == "auth":
418
+ self.set("security.auth.enabled", False)
419
+ elif feature == "roles":
420
+ self.set("security.permissions.enabled", False)
421
+ self.set("roles.enabled", False)
422
+ elif feature == "proxy_registration":
423
+ self.set("proxy_registration.enabled", False)
424
+ elif feature == "security":
425
+ self.set("security.enabled", False)
426
+ elif feature == "rate_limit":
427
+ self.set("security.rate_limit.enabled", False)
428
+ elif feature == "certificates":
429
+ self.set("security.certificates.enabled", False)
430
+ else:
431
+ raise ValueError(f"Unknown feature: {feature}")
432
+
433
+ def is_feature_enabled(self, feature: str) -> bool:
434
+ """
435
+ Check if a specific feature is enabled.
436
+
437
+ Args:
438
+ feature: Feature to check (ssl, auth, roles, proxy_registration,
439
+ security)
440
+
441
+ Returns:
442
+ True if feature is enabled, False otherwise
443
+ """
444
+ if feature == "ssl":
445
+ return (self.get("ssl.enabled", False) or
446
+ self.get("security.ssl.enabled", False))
447
+ elif feature == "auth":
448
+ return self.get("security.auth.enabled", False)
449
+ elif feature == "roles":
450
+ return (self.get("security.permissions.enabled", False) or
451
+ self.get("roles.enabled", False))
452
+ elif feature == "proxy_registration":
453
+ return self.get("proxy_registration.enabled", False)
454
+ elif feature == "security":
455
+ return self.get("security.enabled", False)
456
+ elif feature == "rate_limit":
457
+ return self.get("security.rate_limit.enabled", False)
458
+ elif feature == "certificates":
459
+ return self.get("security.certificates.enabled", False)
460
+ else:
461
+ raise ValueError(f"Unknown feature: {feature}")
462
+
463
+ def get_enabled_features(self) -> List[str]:
464
+ """
465
+ Get list of all enabled features.
466
+
467
+ Returns:
468
+ List of enabled feature names
469
+ """
470
+ features = []
471
+ if self.is_feature_enabled("ssl"):
472
+ features.append("ssl")
473
+ if self.is_feature_enabled("auth"):
474
+ features.append("auth")
475
+ if self.is_feature_enabled("roles"):
476
+ features.append("roles")
477
+ if self.is_feature_enabled("proxy_registration"):
478
+ features.append("proxy_registration")
479
+ if self.is_feature_enabled("security"):
480
+ features.append("security")
481
+ if self.is_feature_enabled("rate_limit"):
482
+ features.append("rate_limit")
483
+ if self.is_feature_enabled("certificates"):
484
+ features.append("certificates")
485
+ return features
486
+
487
+ def configure_auth_mode(self, mode: str, **kwargs) -> None:
488
+ """
489
+ Configure authentication mode.
490
+
491
+ Args:
492
+ mode: Authentication mode (api_key, jwt, certificate, basic, oauth2)
493
+ **kwargs: Additional configuration parameters
494
+ """
495
+ if mode == "api_key":
496
+ self.set("security.auth.methods", ["api_key"])
497
+ if "api_keys" in kwargs:
498
+ self.set("security.auth.api_keys", kwargs["api_keys"])
499
+ elif mode == "jwt":
500
+ self.set("security.auth.methods", ["jwt"])
501
+ if "jwt_secret" in kwargs:
502
+ self.set("security.auth.jwt_secret", kwargs["jwt_secret"])
503
+ elif mode == "certificate":
504
+ self.set("security.auth.methods", ["certificate"])
505
+ self.set("security.auth.certificate_auth", True)
506
+ elif mode == "basic":
507
+ self.set("security.auth.methods", ["basic"])
508
+ self.set("security.auth.basic_auth", True)
509
+ elif mode == "oauth2":
510
+ self.set("security.auth.methods", ["oauth2"])
511
+ if "oauth2_config" in kwargs:
512
+ self.set("security.auth.oauth2_config", kwargs["oauth2_config"])
513
+ else:
514
+ raise ValueError(f"Unknown authentication mode: {mode}")
515
+
516
+ def configure_proxy_registration_mode(self, mode: str, **kwargs) -> None:
517
+ """
518
+ Configure proxy registration mode.
519
+
520
+ Args:
521
+ mode: Registration mode (token, certificate, api_key, none)
522
+ **kwargs: Additional configuration parameters
523
+ """
524
+ if mode == "none":
525
+ self.set("proxy_registration.enabled", False)
526
+ else:
527
+ self.set("proxy_registration.enabled", True)
528
+
529
+ if mode == "token":
530
+ self.set("proxy_registration.auth_method", "token")
531
+ if "token" in kwargs:
532
+ self.set("proxy_registration.token.token", kwargs["token"])
533
+ elif mode == "certificate":
534
+ self.set("proxy_registration.auth_method", "certificate")
535
+ if "cert_file" in kwargs:
536
+ self.set("proxy_registration.certificate.cert_file",
537
+ kwargs["cert_file"])
538
+ if "key_file" in kwargs:
539
+ self.set("proxy_registration.certificate.key_file",
540
+ kwargs["key_file"])
541
+ elif mode == "api_key":
542
+ self.set("proxy_registration.auth_method", "api_key")
543
+ if "key" in kwargs:
544
+ self.set("proxy_registration.api_key.key", kwargs["key"])
545
+
546
+ def create_minimal_config(self) -> Dict[str, Any]:
547
+ """
548
+ Create minimal configuration with only essential features.
549
+
550
+ Returns:
551
+ Minimal configuration dictionary
552
+ """
553
+ minimal_config = self.config_data.copy()
554
+
555
+ # Disable all optional features
556
+ minimal_config["ssl"]["enabled"] = False
557
+ minimal_config["security"]["enabled"] = False
558
+ minimal_config["security"]["auth"]["enabled"] = False
559
+ minimal_config["security"]["permissions"]["enabled"] = False
560
+ minimal_config["security"]["rate_limit"]["enabled"] = False
561
+ minimal_config["security"]["certificates"]["enabled"] = False
562
+ minimal_config["proxy_registration"]["enabled"] = False
563
+ minimal_config["roles"]["enabled"] = False
564
+
565
+ return minimal_config
566
+
567
+ def create_secure_config(self) -> Dict[str, Any]:
568
+ """
569
+ Create secure configuration with all security features enabled.
570
+
571
+ Returns:
572
+ Secure configuration dictionary
573
+ """
574
+ secure_config = self.config_data.copy()
575
+
576
+ # Enable all security features
577
+ secure_config["ssl"]["enabled"] = True
578
+ secure_config["security"]["enabled"] = True
579
+ secure_config["security"]["auth"]["enabled"] = True
580
+ secure_config["security"]["permissions"]["enabled"] = True
581
+ secure_config["security"]["rate_limit"]["enabled"] = True
582
+ secure_config["security"]["certificates"]["enabled"] = True
583
+ secure_config["proxy_registration"]["enabled"] = True
584
+ secure_config["roles"]["enabled"] = True
585
+
586
+ return secure_config
587
+
377
588
 
378
589
  # Singleton instance
379
590
  config = Config()
@@ -35,28 +35,28 @@ class ProtocolManager:
35
35
  """Load protocol configuration from config."""
36
36
  # Use provided config or fallback to global config; normalize types
37
37
  current_config = self.app_config if self.app_config is not None else config.get_all()
38
- logger.info(f"ProtocolManager._load_config - current_config type: {type(current_config)}")
38
+ logger.debug(f"ProtocolManager._load_config - current_config type: {type(current_config)}")
39
39
 
40
40
  if not hasattr(current_config, 'get'):
41
41
  # Not a dict-like config, fallback to global
42
- logger.info(f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config")
42
+ logger.debug(f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config")
43
43
  current_config = config.get_all()
44
44
 
45
- logger.info(f"ProtocolManager._load_config - final current_config type: {type(current_config)}")
45
+ logger.debug(f"ProtocolManager._load_config - final current_config type: {type(current_config)}")
46
46
  if hasattr(current_config, 'get'):
47
- logger.info(f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}")
47
+ logger.debug(f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}")
48
48
 
49
49
  # Get protocols configuration
50
- logger.info(f"ProtocolManager._load_config - before getting protocols")
50
+ logger.debug(f"ProtocolManager._load_config - before getting protocols")
51
51
  try:
52
52
  self.protocols_config = current_config.get("protocols", {})
53
- logger.info(f"ProtocolManager._load_config - protocols_config type: {type(self.protocols_config)}")
53
+ logger.debug(f"ProtocolManager._load_config - protocols_config type: {type(self.protocols_config)}")
54
54
  if hasattr(self.protocols_config, 'get'):
55
- logger.info(f"ProtocolManager._load_config - protocols_config is dict-like")
55
+ logger.debug(f"ProtocolManager._load_config - protocols_config is dict-like")
56
56
  else:
57
- logger.info(f"ProtocolManager._load_config - protocols_config is NOT dict-like: {repr(self.protocols_config)}")
57
+ logger.debug(f"ProtocolManager._load_config - protocols_config is NOT dict-like: {repr(self.protocols_config)}")
58
58
  except Exception as e:
59
- logger.info(f"ProtocolManager._load_config - ERROR getting protocols: {e}")
59
+ logger.debug(f"ProtocolManager._load_config - ERROR getting protocols: {e}")
60
60
  self.protocols_config = {}
61
61
 
62
62
  self.enabled = self.protocols_config.get("enabled", True) if hasattr(self.protocols_config, 'get') else True
@@ -466,18 +466,13 @@ class SimpleCertificateCreator:
466
466
  shutil.copy2(ca_cert, expected_ca_cert)
467
467
  print(f"✅ Created CA certificate copy: {expected_ca_cert}")
468
468
 
469
- # Server certificate symlink
469
+ # Server certificate copy
470
470
  server_cert = self.certs_dir / "server_cert.pem"
471
471
  expected_server_cert = self.certs_dir / "localhost_server.crt"
472
472
  if server_cert.exists() and not expected_server_cert.exists():
473
- try:
474
- expected_server_cert.symlink_to(server_cert)
475
- print(f"✅ Created server certificate symlink: {expected_server_cert}")
476
- except OSError:
477
- # On Windows, symlink might require admin privileges, copy instead
478
- import shutil
479
- shutil.copy2(server_cert, expected_server_cert)
480
- print(f"✅ Created server certificate copy: {expected_server_cert}")
473
+ import shutil
474
+ shutil.copy2(server_cert, expected_server_cert)
475
+ print(f"✅ Created server certificate copy: {expected_server_cert}")
481
476
 
482
477
  # Server key symlink - check if it's in certs or keys directory
483
478
  server_key_certs = self.certs_dir / "server_key.pem"
@@ -492,14 +487,9 @@ class SimpleCertificateCreator:
492
487
  if server_key_keys.exists():
493
488
  expected_server_key = self.keys_dir / "localhost_server.key"
494
489
  if not expected_server_key.exists():
495
- try:
496
- expected_server_key.symlink_to(server_key_keys)
497
- print(f"✅ Created server key symlink: {expected_server_key}")
498
- except OSError:
499
- # On Windows, symlink might require admin privileges, copy instead
500
- import shutil
501
- shutil.copy2(server_key_keys, expected_server_key)
502
- print(f"✅ Created server key copy: {expected_server_key}")
490
+ import shutil
491
+ shutil.copy2(server_key_keys, expected_server_key)
492
+ print(f"✅ Created server key copy: {expected_server_key}")
503
493
 
504
494
  # Print summary
505
495
  print("\n" + "=" * 60)
@@ -0,0 +1,9 @@
1
+ """Basic Framework Example.
2
+
3
+ This example demonstrates the fundamental usage of MCP Proxy Adapter
4
+ with minimal configuration and basic command registration.
5
+
6
+ Note: This package provides a basic example of MCP Proxy Adapter usage.
7
+ The main application is created dynamically in main.py and not exported
8
+ as a global variable for this example.
9
+ """
@@ -0,0 +1,4 @@
1
+ """Basic Framework Commands.
2
+
3
+ Commands for the basic framework example.
4
+ """
@@ -0,0 +1,4 @@
1
+ """Basic Framework Hooks.
2
+
3
+ Hooks for the basic framework example.
4
+ """
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Basic Framework Example
4
+ This example demonstrates the basic usage of the MCP Proxy Adapter framework
5
+ with minimal configuration and built-in commands.
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+ import sys
10
+ import argparse
11
+ from pathlib import Path
12
+ # Add the framework to the path
13
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent))
14
+ from mcp_proxy_adapter.core.app_factory import create_and_run_server
15
+ def main():
16
+ """Main entry point for the basic framework example."""
17
+ parser = argparse.ArgumentParser(description="Basic Framework Example")
18
+ parser.add_argument("--config", "-c", required=True, help="Path to configuration file")
19
+ parser.add_argument("--host", help="Server host")
20
+ parser.add_argument("--port", type=int, help="Server port")
21
+ parser.add_argument("--debug", action="store_true", help="Enable debug mode")
22
+ args = parser.parse_args()
23
+ # Override configuration if specified
24
+ config_overrides = {}
25
+ if args.host:
26
+ config_overrides["host"] = args.host
27
+ if args.port:
28
+ config_overrides["port"] = args.port
29
+ if args.debug:
30
+ config_overrides["debug"] = True
31
+ print(f"🚀 Starting Basic Framework Example")
32
+ print(f"📋 Configuration: {args.config}")
33
+ print("=" * 50)
34
+ # Use the factory method to create and run the server
35
+ create_and_run_server(
36
+ config_path=args.config,
37
+ title="Basic Framework Example",
38
+ description="Basic MCP Proxy Adapter with minimal configuration",
39
+ version="1.0.0",
40
+ host=config_overrides.get("host", "0.0.0.0"),
41
+ log_level="debug" if config_overrides.get("debug", False) else "info"
42
+ )
43
+ if __name__ == "__main__":
44
+ main()
@@ -0,0 +1,12 @@
1
+ """Full Application Example.
2
+
3
+ This example demonstrates advanced usage of MCP Proxy Adapter including:
4
+ - Proxy registration endpoints
5
+ - Custom command hooks
6
+ - Advanced security configurations
7
+ - Role-based access control
8
+ """
9
+
10
+ from .main import get_app
11
+ app = get_app()
12
+ from .proxy_endpoints import router as proxy_router
@@ -0,0 +1,7 @@
1
+ """Full Application Commands.
2
+
3
+ Custom command implementations for the full application example.
4
+ """
5
+
6
+ from .custom_echo_command import CustomEchoCommand
7
+ from .dynamic_calculator_command import DynamicCalculatorCommand