mcp-proxy-adapter 6.9.27__py3-none-any.whl → 6.9.29__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.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +10 -0
- mcp_proxy_adapter/__main__.py +8 -21
- mcp_proxy_adapter/api/app.py +10 -913
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +243 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_manager.py +166 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +78 -199
- mcp_proxy_adapter/api/middleware/__init__.py +1 -44
- mcp_proxy_adapter/api/middleware/base.py +0 -42
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
- mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
- mcp_proxy_adapter/api/middleware/factory.py +0 -94
- mcp_proxy_adapter/api/middleware/logging.py +0 -112
- mcp_proxy_adapter/api/middleware/performance.py +0 -35
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
- mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
- mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +0 -61
- mcp_proxy_adapter/api/tool_integration.py +0 -117
- mcp_proxy_adapter/api/tools.py +0 -46
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +128 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +324 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
- mcp_proxy_adapter/client/proxy.py +45 -0
- mcp_proxy_adapter/commands/__init__.py +44 -28
- mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
- mcp_proxy_adapter/commands/base.py +19 -43
- mcp_proxy_adapter/commands/builtin_commands.py +0 -75
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +58 -928
- mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
- mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
- mcp_proxy_adapter/commands/command_registry.py +172 -904
- mcp_proxy_adapter/commands/config_command.py +0 -28
- mcp_proxy_adapter/commands/dependency_container.py +1 -70
- mcp_proxy_adapter/commands/dependency_manager.py +0 -128
- mcp_proxy_adapter/commands/echo_command.py +0 -34
- mcp_proxy_adapter/commands/health_command.py +0 -3
- mcp_proxy_adapter/commands/help_command.py +0 -159
- mcp_proxy_adapter/commands/hooks.py +0 -137
- mcp_proxy_adapter/commands/key_management_command.py +0 -25
- mcp_proxy_adapter/commands/load_command.py +7 -78
- mcp_proxy_adapter/commands/plugins_command.py +0 -16
- mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
- mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +0 -43
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +0 -80
- mcp_proxy_adapter/commands/result.py +25 -77
- mcp_proxy_adapter/commands/role_test_command.py +0 -44
- mcp_proxy_adapter/commands/roles_management_command.py +0 -199
- mcp_proxy_adapter/commands/security_command.py +0 -30
- mcp_proxy_adapter/commands/settings_command.py +0 -68
- mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
- mcp_proxy_adapter/commands/token_management_command.py +0 -1
- mcp_proxy_adapter/commands/transport_management_command.py +0 -20
- mcp_proxy_adapter/commands/unload_command.py +0 -71
- mcp_proxy_adapter/config.py +15 -626
- mcp_proxy_adapter/core/__init__.py +5 -39
- mcp_proxy_adapter/core/app_factory.py +14 -36
- mcp_proxy_adapter/core/app_runner.py +0 -27
- mcp_proxy_adapter/core/auth_validator.py +1 -93
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
- mcp_proxy_adapter/core/certificate_utils.py +64 -903
- mcp_proxy_adapter/core/client.py +0 -6
- mcp_proxy_adapter/core/client_manager.py +0 -19
- mcp_proxy_adapter/core/client_security.py +0 -2
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +195 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +112 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
- mcp_proxy_adapter/core/config_converter.py +0 -186
- mcp_proxy_adapter/core/config_validator.py +96 -1238
- mcp_proxy_adapter/core/errors.py +7 -42
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +2 -22
- mcp_proxy_adapter/core/mtls_asgi.py +0 -20
- mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
- mcp_proxy_adapter/core/mtls_proxy.py +0 -80
- mcp_proxy_adapter/core/mtls_server.py +3 -173
- mcp_proxy_adapter/core/protocol_manager.py +1 -191
- mcp_proxy_adapter/core/proxy/__init__.py +22 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +0 -1
- mcp_proxy_adapter/core/proxy_registration.py +36 -912
- mcp_proxy_adapter/core/role_utils.py +0 -308
- mcp_proxy_adapter/core/security_adapter.py +1 -36
- mcp_proxy_adapter/core/security_factory.py +1 -150
- mcp_proxy_adapter/core/security_integration.py +0 -33
- mcp_proxy_adapter/core/server_adapter.py +1 -40
- mcp_proxy_adapter/core/server_engine.py +2 -173
- mcp_proxy_adapter/core/settings.py +0 -127
- mcp_proxy_adapter/core/signal_handler.py +0 -65
- mcp_proxy_adapter/core/ssl_utils.py +19 -137
- mcp_proxy_adapter/core/transport_manager.py +0 -151
- mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
- mcp_proxy_adapter/core/utils.py +1 -182
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +211 -0
- mcp_proxy_adapter/core/validation/file_validator.py +73 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
- mcp_proxy_adapter/core/validation/security_validator.py +58 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +33 -652
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
- mcp_proxy_adapter/examples/check_config.py +0 -2
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/config_builder.py +13 -2
- mcp_proxy_adapter/examples/config_cli.py +0 -1
- mcp_proxy_adapter/examples/create_test_configs.py +0 -46
- mcp_proxy_adapter/examples/debug_request_state.py +0 -1
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
- mcp_proxy_adapter/examples/full_application/main.py +186 -150
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
- mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
- mcp_proxy_adapter/examples/generate_config.py +65 -11
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +0 -2
- mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
- mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +24 -1075
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
- mcp_proxy_adapter/examples/test_config.py +0 -3
- mcp_proxy_adapter/examples/test_config_builder.py +25 -405
- mcp_proxy_adapter/examples/test_examples.py +0 -1
- mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
- mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
- mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
- mcp_proxy_adapter/examples/universal_client.py +0 -6
- mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +70 -62
- mcp_proxy_adapter/openapi.py +0 -22
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.9.29.dist-info/RECORD +235 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/entry_points.txt +1 -1
- mcp_proxy_adapter-6.9.27.dist-info/RECORD +0 -149
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,6 @@ email: vasilyvz@gmail.com
|
|
|
10
10
|
import json
|
|
11
11
|
import sys
|
|
12
12
|
from pathlib import Path
|
|
13
|
-
from typing import Dict, Any, List
|
|
14
13
|
|
|
15
14
|
# Add the project root to the path
|
|
16
15
|
project_root = Path(__file__).parent.parent.parent
|
|
@@ -20,196 +19,10 @@ from mcp_proxy_adapter.core.config_validator import ConfigValidator
|
|
|
20
19
|
from mcp_proxy_adapter.examples.config_builder import generate_complete_config
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
def test_generator_validator_structure():
|
|
24
|
-
"""Test that generated configs have the correct structure."""
|
|
25
|
-
print("🔍 Testing Generator-Validator Structure Compatibility")
|
|
26
|
-
print("=" * 60)
|
|
27
|
-
|
|
28
|
-
# Test basic HTTP configuration
|
|
29
|
-
print("\n📋 Testing: HTTP Basic Configuration")
|
|
30
|
-
print("-" * 40)
|
|
31
|
-
|
|
32
|
-
try:
|
|
33
|
-
# Generate configuration
|
|
34
|
-
print(" 🔧 Generating configuration...")
|
|
35
|
-
config = generate_complete_config(host="localhost", port=8080)
|
|
36
|
-
|
|
37
|
-
# Check required sections exist
|
|
38
|
-
required_sections = ["server", "logging", "commands", "debug", "ssl", "security", "roles", "proxy_registration"]
|
|
39
|
-
missing_sections = []
|
|
40
|
-
|
|
41
|
-
for section in required_sections:
|
|
42
|
-
if section not in config:
|
|
43
|
-
missing_sections.append(section)
|
|
44
|
-
|
|
45
|
-
if missing_sections:
|
|
46
|
-
print(f" ❌ FAIL - Missing sections: {missing_sections}")
|
|
47
|
-
return False
|
|
48
|
-
|
|
49
|
-
# Check server section
|
|
50
|
-
server_required = ["host", "port", "protocol", "debug", "log_level"]
|
|
51
|
-
server_missing = [key for key in server_required if key not in config["server"]]
|
|
52
|
-
|
|
53
|
-
if server_missing:
|
|
54
|
-
print(f" ❌ FAIL - Server section missing keys: {server_missing}")
|
|
55
|
-
return False
|
|
56
|
-
|
|
57
|
-
# Check protocol is HTTP
|
|
58
|
-
if config["server"]["protocol"] != "http":
|
|
59
|
-
print(f" ❌ FAIL - Expected protocol 'http', got '{config['server']['protocol']}'")
|
|
60
|
-
return False
|
|
61
|
-
|
|
62
|
-
# Check SSL is disabled
|
|
63
|
-
if config["ssl"]["enabled"] != False:
|
|
64
|
-
print(f" ❌ FAIL - Expected SSL disabled, got {config['ssl']['enabled']}")
|
|
65
|
-
return False
|
|
66
|
-
|
|
67
|
-
# Check security is disabled
|
|
68
|
-
if config["security"]["enabled"] != False:
|
|
69
|
-
print(f" ❌ FAIL - Expected security disabled, got {config['security']['enabled']}")
|
|
70
|
-
return False
|
|
71
|
-
|
|
72
|
-
# Check roles is disabled
|
|
73
|
-
if config["roles"]["enabled"] != False:
|
|
74
|
-
print(f" ❌ FAIL - Expected roles disabled, got {config['roles']['enabled']}")
|
|
75
|
-
return False
|
|
76
|
-
|
|
77
|
-
# Check proxy registration is disabled
|
|
78
|
-
if config["proxy_registration"]["enabled"] != False:
|
|
79
|
-
print(f" ❌ FAIL - Expected proxy registration disabled, got {config['proxy_registration']['enabled']}")
|
|
80
|
-
return False
|
|
81
|
-
|
|
82
|
-
print(" ✅ PASS - All required sections and fields present")
|
|
83
|
-
print(" ✅ PASS - All features correctly disabled")
|
|
84
|
-
print(" ✅ PASS - Protocol correctly set to HTTP")
|
|
85
|
-
|
|
86
|
-
return True
|
|
87
|
-
|
|
88
|
-
except Exception as e:
|
|
89
|
-
print(f" 💥 EXCEPTION: {str(e)}")
|
|
90
|
-
return False
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def test_config_modification():
|
|
94
|
-
"""Test that we can modify generated configs for different scenarios."""
|
|
95
|
-
print("\n📋 Testing: Configuration Modification")
|
|
96
|
-
print("-" * 40)
|
|
97
|
-
|
|
98
|
-
try:
|
|
99
|
-
# Generate base config
|
|
100
|
-
config = generate_complete_config(host="localhost", port=8080)
|
|
101
|
-
|
|
102
|
-
# Test 1: Enable HTTPS
|
|
103
|
-
print(" 🔧 Testing HTTPS modification...")
|
|
104
|
-
config["server"]["protocol"] = "https"
|
|
105
|
-
config["ssl"]["enabled"] = True
|
|
106
|
-
|
|
107
|
-
if config["server"]["protocol"] != "https":
|
|
108
|
-
print(" ❌ FAIL - Could not change protocol to HTTPS")
|
|
109
|
-
return False
|
|
110
|
-
|
|
111
|
-
if config["ssl"]["enabled"] != True:
|
|
112
|
-
print(" ❌ FAIL - Could not enable SSL")
|
|
113
|
-
return False
|
|
114
|
-
|
|
115
|
-
print(" ✅ PASS - HTTPS modification successful")
|
|
116
|
-
|
|
117
|
-
# Test 2: Enable security
|
|
118
|
-
print(" 🔧 Testing security modification...")
|
|
119
|
-
config["security"]["enabled"] = True
|
|
120
|
-
config["security"]["tokens"] = {"test_token": {"permissions": ["*"]}}
|
|
121
|
-
|
|
122
|
-
if config["security"]["enabled"] != True:
|
|
123
|
-
print(" ❌ FAIL - Could not enable security")
|
|
124
|
-
return False
|
|
125
|
-
|
|
126
|
-
if "tokens" not in config["security"]:
|
|
127
|
-
print(" ❌ FAIL - Could not add tokens")
|
|
128
|
-
return False
|
|
129
|
-
|
|
130
|
-
print(" ✅ PASS - Security modification successful")
|
|
131
|
-
|
|
132
|
-
# Test 3: Enable roles
|
|
133
|
-
print(" 🔧 Testing roles modification...")
|
|
134
|
-
config["roles"]["enabled"] = True
|
|
135
|
-
config["roles"]["config_file"] = "./test_roles.json"
|
|
136
|
-
|
|
137
|
-
if config["roles"]["enabled"] != True:
|
|
138
|
-
print(" ❌ FAIL - Could not enable roles")
|
|
139
|
-
return False
|
|
140
|
-
|
|
141
|
-
if config["roles"]["config_file"] != "./test_roles.json":
|
|
142
|
-
print(" ❌ FAIL - Could not set roles config file")
|
|
143
|
-
return False
|
|
144
|
-
|
|
145
|
-
print(" ✅ PASS - Roles modification successful")
|
|
146
|
-
|
|
147
|
-
return True
|
|
148
|
-
|
|
149
|
-
except Exception as e:
|
|
150
|
-
print(f" 💥 EXCEPTION: {str(e)}")
|
|
151
|
-
return False
|
|
152
22
|
|
|
153
23
|
|
|
154
|
-
def test_validator_accepts_generated_config():
|
|
155
|
-
"""Test that validator accepts the basic generated config without file checks."""
|
|
156
|
-
print("\n📋 Testing: Validator Accepts Generated Config")
|
|
157
|
-
print("-" * 40)
|
|
158
|
-
|
|
159
|
-
try:
|
|
160
|
-
# Generate config
|
|
161
|
-
config = generate_complete_config(host="localhost", port=8080)
|
|
162
|
-
|
|
163
|
-
# Create a mock validator that doesn't check files
|
|
164
|
-
class MockValidator(ConfigValidator):
|
|
165
|
-
def _validate_file_existence(self):
|
|
166
|
-
"""Skip file existence checks for testing."""
|
|
167
|
-
pass
|
|
168
|
-
|
|
169
|
-
def _validate_certificate_file(self, cert_file, section, key):
|
|
170
|
-
"""Skip certificate validation for testing."""
|
|
171
|
-
pass
|
|
172
|
-
|
|
173
|
-
def _validate_key_file(self, key_file, section, key):
|
|
174
|
-
"""Skip key validation for testing."""
|
|
175
|
-
pass
|
|
176
|
-
|
|
177
|
-
def _validate_ca_certificate_file(self, ca_cert_file, section, key):
|
|
178
|
-
"""Skip CA certificate validation for testing."""
|
|
179
|
-
pass
|
|
180
|
-
|
|
181
|
-
# Validate with mock validator
|
|
182
|
-
validator = MockValidator()
|
|
183
|
-
validator.config_data = config
|
|
184
|
-
results = validator.validate_config()
|
|
185
|
-
|
|
186
|
-
errors = [r for r in results if r.level == "error"]
|
|
187
|
-
warnings = [r for r in results if r.level == "warning"]
|
|
188
|
-
|
|
189
|
-
if len(errors) > 0:
|
|
190
|
-
print(f" ❌ FAIL - {len(errors)} validation errors:")
|
|
191
|
-
for error in errors[:3]:
|
|
192
|
-
print(f" • {error.message}")
|
|
193
|
-
return False
|
|
194
|
-
|
|
195
|
-
print(f" ✅ PASS - No validation errors ({len(warnings)} warnings)")
|
|
196
|
-
return True
|
|
197
|
-
|
|
198
|
-
except Exception as e:
|
|
199
|
-
print(f" 💥 EXCEPTION: {str(e)}")
|
|
200
|
-
return False
|
|
201
24
|
|
|
202
25
|
|
|
203
|
-
def main():
|
|
204
|
-
"""Main test function."""
|
|
205
|
-
print("🚀 Generator-Validator Structure Compatibility Test")
|
|
206
|
-
print("=" * 70)
|
|
207
|
-
|
|
208
|
-
tests = [
|
|
209
|
-
("Structure Test", test_generator_validator_structure),
|
|
210
|
-
("Modification Test", test_config_modification),
|
|
211
|
-
("Validator Acceptance Test", test_validator_accepts_generated_config)
|
|
212
|
-
]
|
|
213
26
|
|
|
214
27
|
results = []
|
|
215
28
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Integration modules for mcp_proxy_adapter.
|
|
3
|
+
|
|
4
|
+
This package contains integrations with external systems and libraries
|
|
5
|
+
to extend the functionality of the MCP Proxy Adapter framework.
|
|
6
|
+
|
|
7
|
+
Author: Vasiliy Zdanovskiy
|
|
8
|
+
email: vasilyvz@gmail.com
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .queuemgr_integration import (
|
|
12
|
+
QueueManagerIntegration,
|
|
13
|
+
QueueJobBase,
|
|
14
|
+
QueueJobResult,
|
|
15
|
+
QueueJobStatus,
|
|
16
|
+
QueueJobError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"QueueManagerIntegration",
|
|
21
|
+
"QueueJobBase",
|
|
22
|
+
"QueueJobResult",
|
|
23
|
+
"QueueJobStatus",
|
|
24
|
+
"QueueJobError",
|
|
25
|
+
]
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Queue Manager Integration for MCP Proxy Adapter.
|
|
3
|
+
|
|
4
|
+
This module provides integration between mcp_proxy_adapter and queuemgr
|
|
5
|
+
for managing background jobs and task queues.
|
|
6
|
+
|
|
7
|
+
Author: Vasiliy Zdanovskiy
|
|
8
|
+
email: vasilyvz@gmail.com
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from contextlib import asynccontextmanager
|
|
14
|
+
from typing import Optional, Dict, Any, Type
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
from queuemgr.jobs.base import QueueJobBase as QueuemgrJobBase
|
|
18
|
+
from queuemgr.core.types import JobStatus as QueuemgrJobStatus
|
|
19
|
+
from queuemgr.exceptions import (
|
|
20
|
+
QueueManagerError,
|
|
21
|
+
JobNotFoundError,
|
|
22
|
+
JobAlreadyExistsError,
|
|
23
|
+
InvalidJobStateError,
|
|
24
|
+
JobExecutionError,
|
|
25
|
+
ProcessControlError,
|
|
26
|
+
ValidationError as QueuemgrValidationError,
|
|
27
|
+
TimeoutError as QueuemgrTimeoutError,
|
|
28
|
+
)
|
|
29
|
+
QUEUEMGR_AVAILABLE = True
|
|
30
|
+
except ImportError as e:
|
|
31
|
+
# Fallback for when queuemgr is not available
|
|
32
|
+
QUEUEMGR_AVAILABLE = False
|
|
33
|
+
QueuemgrJobBase = object
|
|
34
|
+
QueuemgrJobStatus = str
|
|
35
|
+
QueueManagerError = Exception
|
|
36
|
+
JobNotFoundError = Exception
|
|
37
|
+
JobAlreadyExistsError = Exception
|
|
38
|
+
InvalidJobStateError = Exception
|
|
39
|
+
JobExecutionError = Exception
|
|
40
|
+
ProcessControlError = Exception
|
|
41
|
+
QueuemgrValidationError = Exception
|
|
42
|
+
QueuemgrTimeoutError = Exception
|
|
43
|
+
|
|
44
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
45
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError, ValidationError
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class QueueJobStatus:
|
|
49
|
+
"""Job status constants for queue integration."""
|
|
50
|
+
|
|
51
|
+
PENDING = "pending"
|
|
52
|
+
RUNNING = "running"
|
|
53
|
+
COMPLETED = "completed"
|
|
54
|
+
FAILED = "failed"
|
|
55
|
+
STOPPED = "stopped"
|
|
56
|
+
DELETED = "deleted"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class QueueJobResult:
|
|
60
|
+
"""Result of a queue job execution."""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
job_id: str,
|
|
65
|
+
status: str,
|
|
66
|
+
result: Optional[Dict[str, Any]] = None,
|
|
67
|
+
error: Optional[str] = None,
|
|
68
|
+
progress: int = 0,
|
|
69
|
+
description: str = "",
|
|
70
|
+
):
|
|
71
|
+
"""
|
|
72
|
+
Initialize queue job result.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
job_id: Unique job identifier
|
|
76
|
+
status: Job status
|
|
77
|
+
result: Job result data
|
|
78
|
+
error: Error message if failed
|
|
79
|
+
progress: Progress percentage (0-100)
|
|
80
|
+
description: Job description
|
|
81
|
+
"""
|
|
82
|
+
self.job_id = job_id
|
|
83
|
+
self.status = status
|
|
84
|
+
self.result = result or {}
|
|
85
|
+
self.error = error
|
|
86
|
+
self.progress = max(0, min(100, progress))
|
|
87
|
+
self.description = description
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class QueueJobError(Exception):
|
|
91
|
+
"""Exception raised for queue job errors."""
|
|
92
|
+
|
|
93
|
+
def __init__(self, job_id: str, message: str, original_error: Optional[Exception] = None):
|
|
94
|
+
"""
|
|
95
|
+
Initialize queue job error.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
job_id: Job identifier that failed
|
|
99
|
+
message: Error message
|
|
100
|
+
original_error: Original exception that caused the error
|
|
101
|
+
"""
|
|
102
|
+
super().__init__(f"Job {job_id}: {message}")
|
|
103
|
+
self.job_id = job_id
|
|
104
|
+
self.original_error = original_error
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class QueueJobBase(QueuemgrJobBase):
|
|
108
|
+
"""
|
|
109
|
+
Base class for MCP Proxy Adapter queue jobs.
|
|
110
|
+
|
|
111
|
+
This class extends the queuemgr QueueJobBase to provide
|
|
112
|
+
MCP-specific functionality and error handling.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def __init__(self, job_id: str, params: Dict[str, Any]):
|
|
116
|
+
"""
|
|
117
|
+
Initialize MCP queue job.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
job_id: Unique job identifier
|
|
121
|
+
params: Job parameters
|
|
122
|
+
"""
|
|
123
|
+
if not QUEUEMGR_AVAILABLE:
|
|
124
|
+
raise MicroserviceError(
|
|
125
|
+
"queuemgr is not available. Install it with: pip install queuemgr>=1.0.5"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
super().__init__(job_id, params)
|
|
129
|
+
self.logger = get_global_logger()
|
|
130
|
+
self.mcp_params = params
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class QueueManagerIntegration:
|
|
136
|
+
"""
|
|
137
|
+
Queue Manager Integration for MCP Proxy Adapter.
|
|
138
|
+
|
|
139
|
+
This class provides a high-level interface for managing
|
|
140
|
+
background jobs using the queuemgr system.
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(
|
|
144
|
+
self,
|
|
145
|
+
registry_path: str = "mcp_queue_registry.jsonl",
|
|
146
|
+
shutdown_timeout: float = 30.0,
|
|
147
|
+
max_concurrent_jobs: int = 10,
|
|
148
|
+
):
|
|
149
|
+
"""
|
|
150
|
+
Initialize queue manager integration.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
registry_path: Path to the queue registry file
|
|
154
|
+
shutdown_timeout: Timeout for graceful shutdown
|
|
155
|
+
max_concurrent_jobs: Maximum number of concurrent jobs
|
|
156
|
+
"""
|
|
157
|
+
if not QUEUEMGR_AVAILABLE:
|
|
158
|
+
raise MicroserviceError(
|
|
159
|
+
"queuemgr is not available. Install it with: pip install queuemgr>=1.0.5"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
self.registry_path = registry_path
|
|
163
|
+
self.shutdown_timeout = shutdown_timeout
|
|
164
|
+
self.max_concurrent_jobs = max_concurrent_jobs
|
|
165
|
+
self.logger = get_global_logger()
|
|
166
|
+
self._queue_system: Optional[AsyncQueueSystem] = None
|
|
167
|
+
self._is_running = False
|
|
168
|
+
|
|
169
|
+
async def start(self) -> None:
|
|
170
|
+
"""Start the queue manager integration."""
|
|
171
|
+
if self._is_running:
|
|
172
|
+
self.logger.warning("Queue manager integration is already running")
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
self._queue_system = AsyncQueueSystem(
|
|
177
|
+
registry_path=self.registry_path,
|
|
178
|
+
shutdown_timeout=self.shutdown_timeout,
|
|
179
|
+
)
|
|
180
|
+
await self._queue_system.start()
|
|
181
|
+
self._is_running = True
|
|
182
|
+
self.logger.info("✅ Queue manager integration started")
|
|
183
|
+
|
|
184
|
+
except Exception as e:
|
|
185
|
+
self.logger.error(f"❌ Failed to start queue manager integration: {e}")
|
|
186
|
+
raise MicroserviceError(f"Failed to start queue manager: {str(e)}")
|
|
187
|
+
|
|
188
|
+
async def stop(self) -> None:
|
|
189
|
+
"""Stop the queue manager integration."""
|
|
190
|
+
if not self._is_running:
|
|
191
|
+
self.logger.warning("Queue manager integration is not running")
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
if self._queue_system:
|
|
196
|
+
await self._queue_system.stop()
|
|
197
|
+
self._is_running = False
|
|
198
|
+
self.logger.info("✅ Queue manager integration stopped")
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
self.logger.error(f"❌ Failed to stop queue manager integration: {e}")
|
|
202
|
+
raise MicroserviceError(f"Failed to stop queue manager: {str(e)}")
|
|
203
|
+
|
|
204
|
+
def is_running(self) -> bool:
|
|
205
|
+
"""Check if the queue manager integration is running."""
|
|
206
|
+
return self._is_running and self._queue_system is not None
|
|
207
|
+
|
|
208
|
+
async def add_job(
|
|
209
|
+
self,
|
|
210
|
+
job_class: Type[QueueJobBase],
|
|
211
|
+
job_id: str,
|
|
212
|
+
params: Dict[str, Any],
|
|
213
|
+
) -> QueueJobResult:
|
|
214
|
+
"""
|
|
215
|
+
Add a job to the queue.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
job_class: Job class to instantiate
|
|
219
|
+
job_id: Unique job identifier
|
|
220
|
+
params: Job parameters
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
QueueJobResult with job information
|
|
224
|
+
|
|
225
|
+
Raises:
|
|
226
|
+
QueueJobError: If job cannot be added
|
|
227
|
+
"""
|
|
228
|
+
if not self.is_running():
|
|
229
|
+
raise QueueJobError(job_id, "Queue manager is not running")
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
await self._queue_system.add_job(job_class, job_id, params)
|
|
233
|
+
return QueueJobResult(
|
|
234
|
+
job_id=job_id,
|
|
235
|
+
status=QueueJobStatus.PENDING,
|
|
236
|
+
description="Job added to queue"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
except JobAlreadyExistsError as e:
|
|
240
|
+
raise QueueJobError(job_id, f"Job already exists: {str(e)}", e)
|
|
241
|
+
except QueuemgrValidationError as e:
|
|
242
|
+
raise QueueJobError(job_id, f"Invalid job parameters: {str(e)}", e)
|
|
243
|
+
except Exception as e:
|
|
244
|
+
raise QueueJobError(job_id, f"Failed to add job: {str(e)}", e)
|
|
245
|
+
|
|
246
|
+
async def start_job(self, job_id: str) -> QueueJobResult:
|
|
247
|
+
"""
|
|
248
|
+
Start a job in the queue.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
job_id: Job identifier to start
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
QueueJobResult with job status
|
|
255
|
+
|
|
256
|
+
Raises:
|
|
257
|
+
QueueJobError: If job cannot be started
|
|
258
|
+
"""
|
|
259
|
+
if not self.is_running():
|
|
260
|
+
raise QueueJobError(job_id, "Queue manager is not running")
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
await self._queue_system.start_job(job_id)
|
|
264
|
+
return QueueJobResult(
|
|
265
|
+
job_id=job_id,
|
|
266
|
+
status=QueueJobStatus.RUNNING,
|
|
267
|
+
description="Job started"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
except JobNotFoundError as e:
|
|
271
|
+
raise QueueJobError(job_id, f"Job not found: {str(e)}", e)
|
|
272
|
+
except InvalidJobStateError as e:
|
|
273
|
+
raise QueueJobError(job_id, f"Invalid job state: {str(e)}", e)
|
|
274
|
+
except Exception as e:
|
|
275
|
+
raise QueueJobError(job_id, f"Failed to start job: {str(e)}", e)
|
|
276
|
+
|
|
277
|
+
async def stop_job(self, job_id: str) -> QueueJobResult:
|
|
278
|
+
"""
|
|
279
|
+
Stop a job in the queue.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
job_id: Job identifier to stop
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
QueueJobResult with job status
|
|
286
|
+
|
|
287
|
+
Raises:
|
|
288
|
+
QueueJobError: If job cannot be stopped
|
|
289
|
+
"""
|
|
290
|
+
if not self.is_running():
|
|
291
|
+
raise QueueJobError(job_id, "Queue manager is not running")
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
await self._queue_system.stop_job(job_id)
|
|
295
|
+
return QueueJobResult(
|
|
296
|
+
job_id=job_id,
|
|
297
|
+
status=QueueJobStatus.STOPPED,
|
|
298
|
+
description="Job stopped"
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
except JobNotFoundError as e:
|
|
302
|
+
raise QueueJobError(job_id, f"Job not found: {str(e)}", e)
|
|
303
|
+
except ProcessControlError as e:
|
|
304
|
+
raise QueueJobError(job_id, f"Process control error: {str(e)}", e)
|
|
305
|
+
except Exception as e:
|
|
306
|
+
raise QueueJobError(job_id, f"Failed to stop job: {str(e)}", e)
|
|
307
|
+
|
|
308
|
+
async def delete_job(self, job_id: str) -> QueueJobResult:
|
|
309
|
+
"""
|
|
310
|
+
Delete a job from the queue.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
job_id: Job identifier to delete
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
QueueJobResult with job status
|
|
317
|
+
|
|
318
|
+
Raises:
|
|
319
|
+
QueueJobError: If job cannot be deleted
|
|
320
|
+
"""
|
|
321
|
+
if not self.is_running():
|
|
322
|
+
raise QueueJobError(job_id, "Queue manager is not running")
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
await self._queue_system.delete_job(job_id)
|
|
326
|
+
return QueueJobResult(
|
|
327
|
+
job_id=job_id,
|
|
328
|
+
status=QueueJobStatus.DELETED,
|
|
329
|
+
description="Job deleted"
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
except JobNotFoundError as e:
|
|
333
|
+
raise QueueJobError(job_id, f"Job not found: {str(e)}", e)
|
|
334
|
+
except Exception as e:
|
|
335
|
+
raise QueueJobError(job_id, f"Failed to delete job: {str(e)}", e)
|
|
336
|
+
|
|
337
|
+
async def get_job_status(self, job_id: str) -> QueueJobResult:
|
|
338
|
+
"""
|
|
339
|
+
Get the status of a job.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
job_id: Job identifier to get status for
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
QueueJobResult with job status and information
|
|
346
|
+
|
|
347
|
+
Raises:
|
|
348
|
+
QueueJobError: If job status cannot be retrieved
|
|
349
|
+
"""
|
|
350
|
+
if not self.is_running():
|
|
351
|
+
raise QueueJobError(job_id, "Queue manager is not running")
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
status_data = await self._queue_system.get_job_status(job_id)
|
|
355
|
+
|
|
356
|
+
# Convert queuemgr status to MCP status
|
|
357
|
+
mcp_status = self._convert_status(status_data.get("status", "unknown"))
|
|
358
|
+
|
|
359
|
+
return QueueJobResult(
|
|
360
|
+
job_id=job_id,
|
|
361
|
+
status=mcp_status,
|
|
362
|
+
result=status_data.get("result", {}),
|
|
363
|
+
error=status_data.get("error"),
|
|
364
|
+
progress=status_data.get("progress", 0),
|
|
365
|
+
description=status_data.get("description", ""),
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
except JobNotFoundError as e:
|
|
369
|
+
raise QueueJobError(job_id, f"Job not found: {str(e)}", e)
|
|
370
|
+
except Exception as e:
|
|
371
|
+
raise QueueJobError(job_id, f"Failed to get job status: {str(e)}", e)
|
|
372
|
+
|
|
373
|
+
async def list_jobs(self) -> List[QueueJobResult]:
|
|
374
|
+
"""
|
|
375
|
+
List all jobs in the queue.
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
List of QueueJobResult objects
|
|
379
|
+
|
|
380
|
+
Raises:
|
|
381
|
+
QueueJobError: If jobs cannot be listed
|
|
382
|
+
"""
|
|
383
|
+
if not self.is_running():
|
|
384
|
+
raise QueueJobError("", "Queue manager is not running")
|
|
385
|
+
|
|
386
|
+
try:
|
|
387
|
+
jobs_data = await self._queue_system.list_jobs()
|
|
388
|
+
|
|
389
|
+
results = []
|
|
390
|
+
for job_data in jobs_data:
|
|
391
|
+
mcp_status = self._convert_status(job_data.get("status", "unknown"))
|
|
392
|
+
results.append(QueueJobResult(
|
|
393
|
+
job_id=job_data.get("job_id", "unknown"),
|
|
394
|
+
status=mcp_status,
|
|
395
|
+
result=job_data.get("result", {}),
|
|
396
|
+
error=job_data.get("error"),
|
|
397
|
+
progress=job_data.get("progress", 0),
|
|
398
|
+
description=job_data.get("description", ""),
|
|
399
|
+
))
|
|
400
|
+
|
|
401
|
+
return results
|
|
402
|
+
|
|
403
|
+
except Exception as e:
|
|
404
|
+
raise QueueJobError("", f"Failed to list jobs: {str(e)}", e)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def _convert_status(self, queuemgr_status: str) -> str:
|
|
408
|
+
"""
|
|
409
|
+
Convert queuemgr status to MCP status.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
queuemgr_status: Status from queuemgr
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
MCP-compatible status
|
|
416
|
+
"""
|
|
417
|
+
status_mapping = {
|
|
418
|
+
"pending": QueueJobStatus.PENDING,
|
|
419
|
+
"running": QueueJobStatus.RUNNING,
|
|
420
|
+
"completed": QueueJobStatus.COMPLETED,
|
|
421
|
+
"failed": QueueJobStatus.FAILED,
|
|
422
|
+
"stopped": QueueJobStatus.STOPPED,
|
|
423
|
+
"deleted": QueueJobStatus.DELETED,
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return status_mapping.get(queuemgr_status.lower(), QueueJobStatus.PENDING)
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
# Global queue manager instance
|
|
430
|
+
_global_queue_manager: Optional[QueueManagerIntegration] = None
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
async def get_global_queue_manager() -> QueueManagerIntegration:
|
|
434
|
+
"""
|
|
435
|
+
Get global queue manager instance, initializing it if necessary.
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
QueueManagerIntegration instance
|
|
439
|
+
|
|
440
|
+
Raises:
|
|
441
|
+
QueueJobError: If queue manager cannot be initialized
|
|
442
|
+
"""
|
|
443
|
+
global _global_queue_manager
|
|
444
|
+
|
|
445
|
+
if _global_queue_manager is None:
|
|
446
|
+
# Initialize with default configuration
|
|
447
|
+
config = {
|
|
448
|
+
"queue_manager": {
|
|
449
|
+
"backend": "memory", # Default to in-memory for simplicity
|
|
450
|
+
"max_workers": 4,
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
_global_queue_manager = QueueManagerIntegration(config)
|
|
454
|
+
await _global_queue_manager.initialize()
|
|
455
|
+
|
|
456
|
+
return _global_queue_manager
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|