mcp-proxy-adapter 6.9.7__py3-none-any.whl → 6.9.10__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.
@@ -388,18 +388,19 @@ def create_app(
388
388
  try:
389
389
  from mcp_proxy_adapter.core.config_validator import ConfigValidator
390
390
 
391
- try:
392
- _validator = ConfigValidator()
393
- except TypeError:
394
- _validator = ConfigValidator(current_config)
395
- _validation = _validator.validate(current_config)
396
- if not _validation.is_valid:
391
+ _validator = ConfigValidator()
392
+ _validator.config_data = current_config
393
+ _validation_results = _validator.validate_config()
394
+ errors = [r for r in _validation_results if r.level == "error"]
395
+ warnings = [r for r in _validation_results if r.level == "warning"]
396
+
397
+ if errors:
397
398
  logger.critical("CRITICAL CONFIG ERROR: Invalid configuration at startup:")
398
- for _e in _validation.errors:
399
- logger.critical(f" - {_e}")
399
+ for _e in errors:
400
+ logger.critical(f" - {_e.message}")
400
401
  raise SystemExit(1)
401
- for _w in _validation.warnings:
402
- logger.warning(f"Config warning: {_w}")
402
+ for _w in warnings:
403
+ logger.warning(f"Config warning: {_w.message}")
403
404
  except Exception as _ex:
404
405
  logger.error(f"Failed to run startup configuration validation: {_ex}")
405
406
 
@@ -312,9 +312,15 @@ class ConfigValidator:
312
312
  ))
313
313
 
314
314
  # Check conditional sections based on feature flags
315
+ protocol = self._get_nested_value_safe("server.protocol", "http")
316
+
315
317
  for feature_name, feature_config in self.feature_flags.items():
316
318
  enabled_key = feature_config["enabled_key"]
317
319
 
320
+ # Skip SSL validation for HTTP protocol
321
+ if feature_name in ["ssl", "transport_ssl"] and protocol not in ["https", "mtls"]:
322
+ continue
323
+
318
324
  # Only check if the enabled key exists in the configuration
319
325
  if not self._has_nested_key(enabled_key):
320
326
  continue
@@ -365,9 +371,15 @@ class ConfigValidator:
365
371
 
366
372
  def _validate_feature_flags(self) -> None:
367
373
  """Validate feature flags and their dependencies."""
374
+ protocol = self._get_nested_value_safe("server.protocol", "http")
375
+
368
376
  for feature_name, feature_config in self.feature_flags.items():
369
377
  enabled_key = feature_config["enabled_key"]
370
378
 
379
+ # Skip SSL validation for HTTP protocol
380
+ if feature_name in ["ssl", "transport_ssl"] and protocol not in ["https", "mtls"]:
381
+ continue
382
+
371
383
  # Check if the enabled key exists in the configuration
372
384
  if not self._has_nested_key(enabled_key):
373
385
  # Skip validation if the feature flag key doesn't exist
@@ -415,6 +427,26 @@ class ConfigValidator:
415
427
  """Validate protocol-specific requirements."""
416
428
  protocol = self._get_nested_value_safe("server.protocol", "http")
417
429
 
430
+ # Check mTLS protocol requirements
431
+ if protocol == "mtls":
432
+ # mTLS requires HTTPS protocol
433
+ if not self._has_nested_key("ssl.enabled"):
434
+ self.validation_results.append(ValidationResult(
435
+ level="error",
436
+ message="mTLS protocol requires SSL configuration",
437
+ section="ssl",
438
+ key="enabled"
439
+ ))
440
+ else:
441
+ ssl_enabled = self._get_nested_value_safe("ssl.enabled", False)
442
+ if not ssl_enabled:
443
+ self.validation_results.append(ValidationResult(
444
+ level="error",
445
+ message="mTLS protocol requires SSL to be enabled",
446
+ section="ssl",
447
+ key="enabled"
448
+ ))
449
+
418
450
  if protocol not in self.protocol_requirements:
419
451
  self.validation_results.append(ValidationResult(
420
452
  level="error",
@@ -471,23 +503,37 @@ class ConfigValidator:
471
503
 
472
504
  def _validate_file_existence(self) -> None:
473
505
  """Validate that all referenced files exist."""
506
+ protocol = self._get_nested_value_safe("server.protocol", "http")
507
+
474
508
  file_keys = [
475
509
  "logging.log_dir",
476
510
  "commands.commands_directory",
477
511
  "commands.catalog_directory",
478
512
  "commands.custom_commands_path",
479
513
  "security.roles_file",
480
- "roles.config_file",
481
- "ssl.cert_file",
482
- "ssl.key_file",
483
- "ssl.ca_cert",
484
- "transport.ssl.cert_file",
485
- "transport.ssl.key_file",
486
- "transport.ssl.ca_cert",
487
- "proxy_registration.certificate.cert_file",
488
- "proxy_registration.certificate.key_file"
514
+ "roles.config_file"
489
515
  ]
490
516
 
517
+ # Only add SSL-related files if protocol requires SSL
518
+ if protocol in ["https", "mtls"]:
519
+ file_keys.extend([
520
+ "ssl.cert_file",
521
+ "ssl.key_file",
522
+ "ssl.ca_cert",
523
+ "transport.ssl.cert_file",
524
+ "transport.ssl.key_file",
525
+ "transport.ssl.ca_cert"
526
+ ])
527
+
528
+ # Only add proxy registration files if proxy registration is enabled
529
+ if self._has_nested_key("proxy_registration.enabled"):
530
+ proxy_enabled = self._get_nested_value_safe("proxy_registration.enabled", False)
531
+ if proxy_enabled:
532
+ file_keys.extend([
533
+ "proxy_registration.certificate.cert_file",
534
+ "proxy_registration.certificate.key_file"
535
+ ])
536
+
491
537
  for file_key in file_keys:
492
538
  file_path = self._get_nested_value(file_key)
493
539
  if file_path and not os.path.exists(file_path):
@@ -539,40 +585,79 @@ class ConfigValidator:
539
585
  registration_enabled = self._get_nested_value_safe("proxy_registration.enabled", False)
540
586
 
541
587
  if registration_enabled:
542
- proxy_url = self._get_nested_value("proxy_registration.proxy_url")
543
- if not proxy_url:
588
+ if not self._has_nested_key("proxy_registration.proxy_url"):
544
589
  self.validation_results.append(ValidationResult(
545
590
  level="error",
546
591
  message="Proxy registration is enabled but proxy_url is not specified",
547
592
  section="proxy_registration",
548
593
  key="proxy_url"
549
594
  ))
595
+ else:
596
+ proxy_url = self._get_nested_value("proxy_registration.proxy_url")
597
+ if not proxy_url:
598
+ self.validation_results.append(ValidationResult(
599
+ level="error",
600
+ message="Proxy registration is enabled but proxy_url is not specified",
601
+ section="proxy_registration",
602
+ key="proxy_url"
603
+ ))
550
604
 
551
605
  # Check authentication method consistency
552
606
  auth_method = self._get_nested_value_safe("proxy_registration.auth_method", "none")
553
607
  if auth_method != "none":
554
608
  if auth_method == "certificate":
555
- cert_file = self._get_nested_value("proxy_registration.certificate.cert_file")
556
- key_file = self._get_nested_value("proxy_registration.certificate.key_file")
557
- if not cert_file or not key_file:
558
- self.validation_results.append(ValidationResult(
559
- level="error",
560
- message="Certificate authentication is enabled but certificate files are not specified",
561
- section="proxy_registration",
562
- key="certificate"
563
- ))
564
- elif auth_method == "token":
565
- token = self._get_nested_value("proxy_registration.token.token")
566
- if not token:
609
+ if not self._has_nested_key("proxy_registration.certificate.cert_file"):
610
+ self.validation_results.append(ValidationResult(
611
+ level="error",
612
+ message="Certificate authentication requires cert_file",
613
+ section="proxy_registration.certificate",
614
+ key="cert_file"
615
+ ))
616
+ else:
617
+ cert_file = self._get_nested_value("proxy_registration.certificate.cert_file")
618
+
619
+ if not self._has_nested_key("proxy_registration.certificate.key_file"):
620
+ self.validation_results.append(ValidationResult(
621
+ level="error",
622
+ message="Certificate authentication requires key_file",
623
+ section="proxy_registration.certificate",
624
+ key="key_file"
625
+ ))
626
+ else:
627
+ key_file = self._get_nested_value("proxy_registration.certificate.key_file")
628
+
629
+ if not cert_file or not key_file:
567
630
  self.validation_results.append(ValidationResult(
568
631
  level="error",
569
- message="Token authentication is enabled but token is not specified",
632
+ message="Certificate authentication is enabled but certificate files are not specified",
570
633
  section="proxy_registration",
634
+ key="certificate"
635
+ ))
636
+ elif auth_method == "token":
637
+ if not self._has_nested_key("proxy_registration.token.token"):
638
+ self.validation_results.append(ValidationResult(
639
+ level="error",
640
+ message="Token authentication requires token",
641
+ section="proxy_registration.token",
571
642
  key="token"
572
643
  ))
644
+ else:
645
+ token = self._get_nested_value("proxy_registration.token.token")
646
+ if not token:
647
+ self.validation_results.append(ValidationResult(
648
+ level="error",
649
+ message="Token authentication is enabled but token is not specified",
650
+ section="proxy_registration",
651
+ key="token"
652
+ ))
573
653
 
574
654
  def _validate_ssl_configuration(self) -> None:
575
655
  """Validate SSL configuration with detailed certificate validation."""
656
+ # Only validate SSL if the protocol requires it
657
+ protocol = self._get_nested_value_safe("server.protocol", "http")
658
+ if protocol not in ["https", "mtls"]:
659
+ return
660
+
576
661
  # Only validate SSL if the ssl section exists
577
662
  if not self._has_nested_key("ssl.enabled"):
578
663
  return
@@ -580,9 +665,35 @@ class ConfigValidator:
580
665
  ssl_enabled = self._get_nested_value_safe("ssl.enabled", False)
581
666
 
582
667
  if ssl_enabled:
583
- cert_file = self._get_nested_value("ssl.cert_file")
584
- key_file = self._get_nested_value("ssl.key_file")
585
- ca_cert = self._get_nested_value("ssl.ca_cert")
668
+ if not self._has_nested_key("ssl.cert_file"):
669
+ self.validation_results.append(ValidationResult(
670
+ level="error",
671
+ message="SSL is enabled but cert_file is not specified",
672
+ section="ssl",
673
+ key="cert_file"
674
+ ))
675
+ else:
676
+ cert_file = self._get_nested_value("ssl.cert_file")
677
+
678
+ if not self._has_nested_key("ssl.key_file"):
679
+ self.validation_results.append(ValidationResult(
680
+ level="error",
681
+ message="SSL is enabled but key_file is not specified",
682
+ section="ssl",
683
+ key="key_file"
684
+ ))
685
+ else:
686
+ key_file = self._get_nested_value("ssl.key_file")
687
+
688
+ if not self._has_nested_key("ssl.ca_cert"):
689
+ self.validation_results.append(ValidationResult(
690
+ level="error",
691
+ message="SSL is enabled but ca_cert is not specified",
692
+ section="ssl",
693
+ key="ca_cert"
694
+ ))
695
+ else:
696
+ ca_cert = self._get_nested_value("ssl.ca_cert")
586
697
 
587
698
  # Check certificate file
588
699
  if not cert_file:
@@ -644,21 +755,29 @@ class ConfigValidator:
644
755
  roles_enabled = self._get_nested_value_safe("roles.enabled", False)
645
756
 
646
757
  if roles_enabled:
647
- config_file = self._get_nested_value("roles.config_file")
648
- if not config_file:
758
+ if not self._has_nested_key("roles.config_file"):
649
759
  self.validation_results.append(ValidationResult(
650
760
  level="error",
651
761
  message="Roles are enabled but config_file is not specified",
652
762
  section="roles",
653
763
  key="config_file"
654
764
  ))
655
- elif not os.path.exists(config_file):
656
- self.validation_results.append(ValidationResult(
657
- level="error",
658
- message=f"Roles config file '{config_file}' does not exist",
659
- section="roles",
660
- key="config_file"
661
- ))
765
+ else:
766
+ config_file = self._get_nested_value("roles.config_file")
767
+ if not config_file:
768
+ self.validation_results.append(ValidationResult(
769
+ level="error",
770
+ message="Roles are enabled but config_file is not specified",
771
+ section="roles",
772
+ key="config_file"
773
+ ))
774
+ elif not os.path.exists(config_file):
775
+ self.validation_results.append(ValidationResult(
776
+ level="error",
777
+ message=f"Roles config file '{config_file}' does not exist",
778
+ section="roles",
779
+ key="config_file"
780
+ ))
662
781
 
663
782
  def _get_nested_value(self, key: str) -> Any:
664
783
  """Get value from nested dictionary using dot notation. Raises exception if key not found."""
@@ -82,6 +82,12 @@ def generate_complete_config(host: str = "0.0.0.0", port: int = 8000) -> Dict[st
82
82
  "enabled": False,
83
83
  "level": "WARNING"
84
84
  },
85
+ "ssl": {
86
+ "enabled": False,
87
+ "cert_file": None,
88
+ "key_file": None,
89
+ "ca_cert": None
90
+ },
85
91
  "security": {
86
92
  "enabled": False,
87
93
  "tokens": {},
@@ -16,7 +16,7 @@ from typing import Dict, Any, Optional
16
16
  # Add the current directory to the path to import config_builder
17
17
  sys.path.insert(0, str(Path(__file__).parent))
18
18
 
19
- from config_builder import ConfigBuilder, ConfigFactory, Protocol, AuthMethod
19
+ from config_builder import generate_complete_config
20
20
 
21
21
  # Import validation modules
22
22
  try:
@@ -57,10 +57,8 @@ def create_config_from_flags(
57
57
  Returns:
58
58
  Configuration dictionary
59
59
  """
60
- # Use the enhanced config builder
61
- from config_builder import create_config_from_flags as enhanced_create_config
62
-
63
- return enhanced_create_config(protocol, token, roles, port, proxy_registration, proxy_url, auto_registration, server_id)
60
+ # Use the simple config builder
61
+ return generate_complete_config(host, port)
64
62
 
65
63
 
66
64
  def save_config(config: Dict[str, Any], filename: str, output_dir: str, validate: bool = True) -> Path:
@@ -2,4 +2,4 @@
2
2
  Version information for MCP Proxy Adapter.
3
3
  """
4
4
 
5
- __version__ = "6.9.7"
5
+ __version__ = "6.9.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.9.7
3
+ Version: 6.9.10
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,9 +4,9 @@ mcp_proxy_adapter/config.py,sha256=1Ngxri2IPGoytYdCF5pXzbLUXsWcf6qYENkaDkAppg0,2
4
4
  mcp_proxy_adapter/custom_openapi.py,sha256=XRviX-C-ZkSKdBhORhDTdeN_1FWyEfXZADiASft3t9I,28149
5
5
  mcp_proxy_adapter/main.py,sha256=NFcSW7WaEnimRWe5zj28D0CH9otHlRZ92d2Um6XiGjE,10399
6
6
  mcp_proxy_adapter/openapi.py,sha256=2UZOI09ZDRJuBYBjKbMyb2U4uASszoCMD5o_4ktRpvg,13480
7
- mcp_proxy_adapter/version.py,sha256=e_sPEsKJLZMvetzVlFPS_CvyEGxkD-vhanbfb-2ii1o,74
7
+ mcp_proxy_adapter/version.py,sha256=sjeaOBDaenC5mbWV1ZBeLLxJEySM3gA0p4Tc6DWCGzU,75
8
8
  mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- mcp_proxy_adapter/api/app.py,sha256=PQ1Ch5ydJIHp3Z6gcMCzKkTsXPQAuZ9weHtQ-EXnNGY,37134
9
+ mcp_proxy_adapter/api/app.py,sha256=La7xt02j4Zbg4sSc1iL72DM3UNFVddPlN4_xpaRauVo,37214
10
10
  mcp_proxy_adapter/api/handlers.py,sha256=X-hcMNVeTAu4yVkKJEChEsj2bFptUS6sLNN-Wysjkow,10011
11
11
  mcp_proxy_adapter/api/schemas.py,sha256=mevUvQnYgWQfkJAs3-vq3HalBzh6-Saa-Au1VVf0peE,12377
12
12
  mcp_proxy_adapter/api/tool_integration.py,sha256=AeUyvJVN-c3FrX5fHdagHL51saRH5d1ZKqc2YEx0rTE,10147
@@ -62,7 +62,7 @@ mcp_proxy_adapter/core/client.py,sha256=qIbPl8prEwK2U65kl-vGJW2_imo1E4i6HxG_VpPe
62
62
  mcp_proxy_adapter/core/client_manager.py,sha256=yD8HZJlOwmDbVU49YfzSbh1XZ-Vib8qfcLVAaH03Jdg,8832
63
63
  mcp_proxy_adapter/core/client_security.py,sha256=siUaYorcDbpZsEIKgLfg-jBKkp7z_Er8wsO63mDD3Is,13127
64
64
  mcp_proxy_adapter/core/config_converter.py,sha256=Wnnsrbw7DxtgDfLG-IyyzK-hkKu0_1yp7-7dW87tu_4,17422
65
- mcp_proxy_adapter/core/config_validator.py,sha256=Jiu3rJ9eJyEUBNsZ88jVQ-cj_Hd5BxhlBbWtyG6QAsA,49313
65
+ mcp_proxy_adapter/core/config_validator.py,sha256=GmzXu7HfPerIwRHuTuELyavAwqUFD2ws_Km2Z2oNOfs,54875
66
66
  mcp_proxy_adapter/core/crl_utils.py,sha256=Jnwq2UN52IoCDZCwByRP3XNMOJexftb-mVaH6zes6Fc,11706
67
67
  mcp_proxy_adapter/core/errors.py,sha256=CyhQgvMt0ooQjONa65XRBJ44y-l-E5_ES4KOuRvIpBk,8557
68
68
  mcp_proxy_adapter/core/logging.py,sha256=VIpiC6QTGLukRjiJoVpq3VEoLKhUeLNl8IdfljpW6ZU,9654
@@ -89,13 +89,13 @@ mcp_proxy_adapter/examples/__init__.py,sha256=k1F-EotAFbJ3JvK_rNgiH4bUztmxIWtYn0
89
89
  mcp_proxy_adapter/examples/bugfix_certificate_config.py,sha256=YGBE_SI6wYZUJLWl7-fP1OWXiSH4mHJAZHApgQWvG7s,10529
90
90
  mcp_proxy_adapter/examples/cert_manager_bugfix.py,sha256=UWUwItjqHqSnOMHocsz40_3deoZE8-vdROLW9y2fEns,7259
91
91
  mcp_proxy_adapter/examples/check_config.py,sha256=oDP3cymq76TqEpPztPihH-_sBktiEb2cG0MdVrY1Sj8,14104
92
- mcp_proxy_adapter/examples/config_builder.py,sha256=1Q84iq2JH6QTyHMUaykjTrdub6-P4jnMcLxfrVkbLSA,6831
92
+ mcp_proxy_adapter/examples/config_builder.py,sha256=z0I5d83kdNVaR1ATaeT_P4jmxBiIcovlNu7-9I6zgcQ,6978
93
93
  mcp_proxy_adapter/examples/config_cli.py,sha256=ZhVG6XEpTFe5-MzELByVsUh0AD4bHPBZeoXnGWbqifs,11059
94
94
  mcp_proxy_adapter/examples/create_test_configs.py,sha256=9TrvLa4-bWLPu0SB1JXwWuCsjj-4Vz3yAdowcHtCSSA,8228
95
95
  mcp_proxy_adapter/examples/debug_request_state.py,sha256=Z3Gy2-fWtu7KIV9OkzGDLVz7TpL_h9V_99ica40uQBU,4489
96
96
  mcp_proxy_adapter/examples/debug_role_chain.py,sha256=GLVXC2fJUwP8UJnXHchd1t-H53cjWLJI3RqTPrKmaak,8750
97
97
  mcp_proxy_adapter/examples/demo_client.py,sha256=en2Rtb70B1sQmhL-vdQ4PDpKNNl_mfll2YCFT_jFCAg,10191
98
- mcp_proxy_adapter/examples/generate_config.py,sha256=45noGYcZbkFGJNf3Qq5T17bL-PDLh5f9o0UE-dNo0eM,15169
98
+ mcp_proxy_adapter/examples/generate_config.py,sha256=h0_T9gi8ux6xf2nIF56VX1s2YBxLxQVIk3SbhmKsxEg,14977
99
99
  mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=vemRhftnjbiOBCJkmtDGqlWQ8syTG0a8755GCOnaQsg,12503
100
100
  mcp_proxy_adapter/examples/required_certificates.py,sha256=YW9-V78oFiZ-FmHlGP-8FQFS569VdDVyq9hfvCv31pk,7133
101
101
  mcp_proxy_adapter/examples/run_example.py,sha256=yp-a6HIrSk3ddQmbn0KkuKwErId0aNfj028TE6U-zmY,2626
@@ -135,8 +135,8 @@ mcp_proxy_adapter/schemas/base_schema.json,sha256=v9G9cGMd4dRhCZsOQ_FMqOi5VFyVbI
135
135
  mcp_proxy_adapter/schemas/openapi_schema.json,sha256=C3yLkwmDsvnLW9B5gnKKdBGl4zxkeU-rEmjTrNVsQU0,8405
136
136
  mcp_proxy_adapter/schemas/roles.json,sha256=pgf_ZyqKyXbfGUxvobpiLiSJz9zzxrMuoVWEkEpz3N8,764
137
137
  mcp_proxy_adapter/schemas/roles_schema.json,sha256=deHgI7L6GwfBXacOlNtDgDJelDThppClC3Ti4Eh8rJY,5659
138
- mcp_proxy_adapter-6.9.7.dist-info/METADATA,sha256=jPv79sUiL5LIIc9uoDBw4i994eFASaTpiJXisdAGz0g,8510
139
- mcp_proxy_adapter-6.9.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
140
- mcp_proxy_adapter-6.9.7.dist-info/entry_points.txt,sha256=Bf-O5Aq80n22Ayu9fI9BgidzWqwzIVaqextAddTuHZw,563
141
- mcp_proxy_adapter-6.9.7.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
142
- mcp_proxy_adapter-6.9.7.dist-info/RECORD,,
138
+ mcp_proxy_adapter-6.9.10.dist-info/METADATA,sha256=h4we7LJB-fUzy2mHfbzo0uJz0Ihc0O10dmVrmYcCxYQ,8511
139
+ mcp_proxy_adapter-6.9.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
140
+ mcp_proxy_adapter-6.9.10.dist-info/entry_points.txt,sha256=Bf-O5Aq80n22Ayu9fI9BgidzWqwzIVaqextAddTuHZw,563
141
+ mcp_proxy_adapter-6.9.10.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
142
+ mcp_proxy_adapter-6.9.10.dist-info/RECORD,,