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.
- mcp_proxy_adapter/api/app.py +27 -10
- mcp_proxy_adapter/commands/command_registry.py +9 -6
- mcp_proxy_adapter/core/config_validator.py +20 -16
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.15.dist-info → mcp_proxy_adapter-6.9.16.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.9.15.dist-info → mcp_proxy_adapter-6.9.16.dist-info}/RECORD +9 -9
- {mcp_proxy_adapter-6.9.15.dist-info → mcp_proxy_adapter-6.9.16.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.15.dist-info → mcp_proxy_adapter-6.9.16.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.9.15.dist-info → mcp_proxy_adapter-6.9.16.dist-info}/top_level.txt +0 -0
mcp_proxy_adapter/api/app.py
CHANGED
@@ -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
|
-
|
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(
|
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
|
-
|
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
|
-
|
684
|
+
config_obj.load_from_file(config_path)
|
682
685
|
logger.info(f"✅ Configuration loaded from: {config_path}")
|
683
686
|
else:
|
684
|
-
|
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(
|
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
|
-
|
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
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
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
|
-
|
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
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
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:
|
mcp_proxy_adapter/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-proxy-adapter
|
3
|
-
Version: 6.9.
|
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=
|
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=
|
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=
|
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
|
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.
|
141
|
-
mcp_proxy_adapter-6.9.
|
142
|
-
mcp_proxy_adapter-6.9.
|
143
|
-
mcp_proxy_adapter-6.9.
|
144
|
-
mcp_proxy_adapter-6.9.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|