mcp-proxy-adapter 6.9.15__py3-none-any.whl → 6.9.16__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.
@@ -116,12 +116,13 @@ def _determine_registration_url(config: Dict[str, Any]) -> str:
116
116
  return server_url
117
117
 
118
118
 
119
- def create_lifespan(config_path: Optional[str] = None):
119
+ def create_lifespan(config_path: Optional[str] = None, current_config: Optional[Dict[str, Any]] = None):
120
120
  """
121
121
  Create lifespan manager for the FastAPI application.
122
122
 
123
123
  Args:
124
124
  config_path: Path to configuration file (optional)
125
+ current_config: Current configuration data (optional)
125
126
 
126
127
  Returns:
127
128
  Lifespan context manager
@@ -146,7 +147,17 @@ def create_lifespan(config_path: Optional[str] = None):
146
147
  # Compute server_url EARLY and inject into registration manager so
147
148
  # that reload_system (which may perform registration) uses the correct
148
149
  # externally reachable address.
149
- server_config = current_config.get("server")
150
+ # Use current_config from closure or fallback to global config
151
+ config_to_use = current_config
152
+ if config_to_use is None:
153
+ # Fallback: try to get config from global instance
154
+ try:
155
+ from mcp_proxy_adapter.config import get_config
156
+ config_to_use = get_config().get_all()
157
+ except Exception:
158
+ config_to_use = {}
159
+
160
+ server_config = config_to_use.get("server")
150
161
  if not server_config:
151
162
  raise ValueError("server configuration is required")
152
163
  server_host = server_config.get("host")
@@ -159,10 +170,6 @@ def create_lifespan(config_path: Optional[str] = None):
159
170
  # Check port availability BEFORE starting registration manager
160
171
  from mcp_proxy_adapter.core.utils import check_port_availability, handle_port_conflict
161
172
 
162
- server_config = config.get("server", {})
163
- server_host = server_config.get("host", "0.0.0.0")
164
- server_port = server_config.get("port", 8000)
165
-
166
173
  print(f"🔍 Checking external server port availability: {server_host}:{server_port}")
167
174
  if not check_port_availability(server_host, server_port):
168
175
  print(f"❌ CRITICAL: External server port {server_port} is occupied")
@@ -171,7 +178,7 @@ def create_lifespan(config_path: Optional[str] = None):
171
178
  print(f"✅ External server port {server_port} is available")
172
179
 
173
180
  # Determine registration URL using unified logic
174
- early_server_url = _determine_registration_url(config)
181
+ early_server_url = _determine_registration_url(config_to_use)
175
182
  try:
176
183
  from mcp_proxy_adapter.core.proxy_registration import (
177
184
  register_with_proxy,
@@ -190,10 +197,20 @@ def create_lifespan(config_path: Optional[str] = None):
190
197
  logger.error(f"Failed to initialize async registration: {e}")
191
198
 
192
199
  # Initialize system using unified logic (may perform registration)
200
+ # Set global config for reload_system
201
+ from mcp_proxy_adapter.config import Config
202
+ config_obj = Config()
203
+ config_obj.config_data = config_to_use
204
+
205
+ # Set global config for command registry
206
+ from mcp_proxy_adapter.config import get_config
207
+ global_config = get_config()
208
+ global_config.config_data = config_to_use
209
+
193
210
  if config_path:
194
- init_result = await registry.reload_system(config_path=config_path)
211
+ init_result = await registry.reload_system(config_path=config_path, config_obj=config_obj)
195
212
  else:
196
- init_result = await registry.reload_system()
213
+ init_result = await registry.reload_system(config_obj=config_obj)
197
214
 
198
215
  logger.info(
199
216
  f"Application started with {init_result['total_commands']} commands registered"
@@ -566,7 +583,7 @@ def create_app(
566
583
  version=app_version,
567
584
  docs_url="/docs",
568
585
  redoc_url="/redoc",
569
- lifespan=create_lifespan(config_path),
586
+ lifespan=create_lifespan(config_path, current_config),
570
587
  )
571
588
 
572
589
  # CRITICAL FIX: Register commands immediately during app creation
@@ -659,7 +659,7 @@ class CommandRegistry:
659
659
  self._loaded_commands.clear()
660
660
  self._instances.clear()
661
661
 
662
- async def reload_system(self, config_path: Optional[str] = None) -> Dict[str, Any]:
662
+ async def reload_system(self, config_path: Optional[str] = None, config_obj: Optional[Any] = None) -> Dict[str, Any]:
663
663
  """
664
664
  Universal method for system initialization and reload.
665
665
  This method should be used both at startup and during reload.
@@ -675,13 +675,16 @@ class CommandRegistry:
675
675
  )
676
676
 
677
677
  # Step 1: Load configuration (preserve previous config for soft-fail)
678
- previous_config = config.get_all()
678
+ if config_obj is None:
679
+ config_obj = config
680
+
681
+ previous_config = config_obj.get_all()
679
682
  try:
680
683
  if config_path:
681
- config.load_from_file(config_path)
684
+ config_obj.load_from_file(config_path)
682
685
  logger.info(f"✅ Configuration loaded from: {config_path}")
683
686
  else:
684
- config.load_config()
687
+ config_obj.load_config()
685
688
  logger.info("✅ Configuration loaded from default path")
686
689
 
687
690
  config_reloaded = True
@@ -694,14 +697,14 @@ class CommandRegistry:
694
697
  from mcp_proxy_adapter.core.config_validator import ConfigValidator
695
698
 
696
699
  validator = ConfigValidator()
697
- validation = validator.validate(config.get_all())
700
+ validation = validator.validate(config_obj.get_all())
698
701
  if not validation.is_valid:
699
702
  logger.error("⚠️ Configuration validation failed during reload:")
700
703
  for err in validation.errors:
701
704
  logger.error(f" - {err}")
702
705
  # Do NOT exit on reload; restore previous configuration
703
706
  try:
704
- config.config_data = previous_config
707
+ config_obj.config_data = previous_config
705
708
  config_reloaded = False
706
709
  logger.error("ℹ️ Restored previous configuration due to validation errors")
707
710
  except Exception as restore_ex:
@@ -341,13 +341,18 @@ class ConfigValidator:
341
341
 
342
342
  section_data = self.config_data[section_name]
343
343
  for key, expected_type in required_keys.items():
344
+ # Check if key allows None (optional)
345
+ is_optional = isinstance(expected_type, tuple) and type(None) in expected_type
346
+
344
347
  if key not in section_data:
345
- self.validation_results.append(ValidationResult(
346
- level="error",
347
- message=f"Required key '{key}' is missing in section '{section_name}' for enabled feature",
348
- section=section_name,
349
- key=key
350
- ))
348
+ # Only report error if key is not optional
349
+ if not is_optional:
350
+ self.validation_results.append(ValidationResult(
351
+ level="error",
352
+ message=f"Required key '{key}' is missing in section '{section_name}' for enabled feature",
353
+ section=section_name,
354
+ key=key
355
+ ))
351
356
  else:
352
357
  # Validate type
353
358
  value = section_data[key]
@@ -535,7 +540,11 @@ class ConfigValidator:
535
540
  ])
536
541
 
537
542
  for file_key in file_keys:
538
- file_path = self._get_nested_value(file_key)
543
+ # Skip if the key doesn't exist in the configuration
544
+ if not self._has_nested_key(file_key):
545
+ continue
546
+
547
+ file_path = self._get_nested_value_safe(file_key)
539
548
  if file_path and not os.path.exists(file_path):
540
549
  # Check if this is a required file based on enabled features
541
550
  is_required = self._is_file_required_for_enabled_features(file_key)
@@ -685,15 +694,10 @@ class ConfigValidator:
685
694
  else:
686
695
  key_file = self._get_nested_value("ssl.key_file")
687
696
 
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")
697
+ # CA cert is optional for HTTPS but may be required for mTLS with client verification
698
+ ca_cert = None
699
+ if self._has_nested_key("ssl.ca_cert"):
700
+ ca_cert = self._get_nested_value_safe("ssl.ca_cert")
697
701
 
698
702
  # Check certificate file
699
703
  if not cert_file:
@@ -2,4 +2,4 @@
2
2
  Version information for MCP Proxy Adapter.
3
3
  """
4
4
 
5
- __version__ = "6.9.15"
5
+ __version__ = "6.9.16"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.9.15
3
+ Version: 6.9.16
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=ow9zL4fRK6vr0ZYukUIGcHo2VKup9NCJqflrDDeGFQU,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=wNd8p-JNrRUaPPjPgiZdeLFjvBYBXlFIAoT2Vcww0L4,75
7
+ mcp_proxy_adapter/version.py,sha256=5LFX-sQkllGH3WMs3H7fc5U7YusbuSm8_dE4BGqPip8,75
8
8
  mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- mcp_proxy_adapter/api/app.py,sha256=FoZ6YU_ZbvWmg_1nz9TQoyu7urd-tDybdLAGrM-moY4,37556
9
+ mcp_proxy_adapter/api/app.py,sha256=5XGhli2MClGfDetSaAhK8oXe7erzUoC4ISytVWIjDbI,38364
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
@@ -29,7 +29,7 @@ mcp_proxy_adapter/commands/builtin_commands.py,sha256=8kYLWIr4JvhZtqaVM9Jhqr_-yS
29
29
  mcp_proxy_adapter/commands/catalog_manager.py,sha256=1DLvjt9RVMmeNZyynd-frk8gYkdgGJYyBXg6uWTJ16k,34873
30
30
  mcp_proxy_adapter/commands/cert_monitor_command.py,sha256=phSms8EYOn1RqSp7na6jw0S1bLRrilmYZIFXVepVFyU,23687
31
31
  mcp_proxy_adapter/commands/certificate_management_command.py,sha256=TDoGV2mnEz1HaJiHsxAO_IvtSinVwp0s_av5oIgmRqk,23225
32
- mcp_proxy_adapter/commands/command_registry.py,sha256=jsvGu50nwQdBCBAZ4i2Kn88RO0eETYT4WY1wwQlJGNw,37517
32
+ mcp_proxy_adapter/commands/command_registry.py,sha256=NpVUCj78M_9BlxlJSAn0v_Mq7sRgmXDqWxAS32hOO7E,37647
33
33
  mcp_proxy_adapter/commands/config_command.py,sha256=PWX1OhKAmjlc8CSy4-sImdvGeSNgDNyv30Y-P5iZp9g,3767
34
34
  mcp_proxy_adapter/commands/dependency_container.py,sha256=mvPob62lQ-mKRbAA9aL3L5gOT9_4V2Vy2cGoup2S840,3239
35
35
  mcp_proxy_adapter/commands/dependency_manager.py,sha256=lXgtrhCiQhy9Y-QpU_RWRg2d0VYy5msoNQPUjPOcOc8,8245
@@ -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=B5Tu8nE_iSvB1jFJ6qseOZrUpd0QoK7phU9Sznv1HDI,54858
65
+ mcp_proxy_adapter/core/config_validator.py,sha256=-pvOeh_7srlpxzTQ7TzsPcEbBzSaltFoPJPgJjcX-zA,55179
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=dplInPvL4Ff4P0cRDszOiCcFzwu7NXAw2qkBB2OW7_E,8452
@@ -137,8 +137,8 @@ mcp_proxy_adapter/schemas/base_schema.json,sha256=v9G9cGMd4dRhCZsOQ_FMqOi5VFyVbI
137
137
  mcp_proxy_adapter/schemas/openapi_schema.json,sha256=C3yLkwmDsvnLW9B5gnKKdBGl4zxkeU-rEmjTrNVsQU0,8405
138
138
  mcp_proxy_adapter/schemas/roles.json,sha256=pgf_ZyqKyXbfGUxvobpiLiSJz9zzxrMuoVWEkEpz3N8,764
139
139
  mcp_proxy_adapter/schemas/roles_schema.json,sha256=deHgI7L6GwfBXacOlNtDgDJelDThppClC3Ti4Eh8rJY,5659
140
- mcp_proxy_adapter-6.9.15.dist-info/METADATA,sha256=6tBPggVIw3Pa8iQmsEPd0kW7mFhW1uAv1HHD5adIop4,8511
141
- mcp_proxy_adapter-6.9.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
142
- mcp_proxy_adapter-6.9.15.dist-info/entry_points.txt,sha256=Bf-O5Aq80n22Ayu9fI9BgidzWqwzIVaqextAddTuHZw,563
143
- mcp_proxy_adapter-6.9.15.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
144
- mcp_proxy_adapter-6.9.15.dist-info/RECORD,,
140
+ mcp_proxy_adapter-6.9.16.dist-info/METADATA,sha256=7B2rZRfRiPEOw4DmLfr-KfrLaLXbfYI6VecB1ocsoSs,8511
141
+ mcp_proxy_adapter-6.9.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
142
+ mcp_proxy_adapter-6.9.16.dist-info/entry_points.txt,sha256=Bf-O5Aq80n22Ayu9fI9BgidzWqwzIVaqextAddTuHZw,563
143
+ mcp_proxy_adapter-6.9.16.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
144
+ mcp_proxy_adapter-6.9.16.dist-info/RECORD,,