mcp-proxy-adapter 4.1.0__py3-none-any.whl → 6.0.0__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/__main__.py +12 -0
- mcp_proxy_adapter/api/app.py +138 -11
- mcp_proxy_adapter/api/handlers.py +16 -1
- mcp_proxy_adapter/api/middleware/__init__.py +30 -29
- mcp_proxy_adapter/api/middleware/auth_adapter.py +235 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
- mcp_proxy_adapter/api/middleware/factory.py +219 -0
- mcp_proxy_adapter/api/middleware/logging.py +32 -6
- mcp_proxy_adapter/api/middleware/mtls_adapter.py +305 -0
- mcp_proxy_adapter/api/middleware/mtls_middleware.py +296 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
- mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +241 -0
- mcp_proxy_adapter/api/middleware/roles_adapter.py +365 -0
- mcp_proxy_adapter/api/middleware/roles_middleware.py +381 -0
- mcp_proxy_adapter/api/middleware/security.py +376 -0
- mcp_proxy_adapter/api/middleware/token_auth_middleware.py +261 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
- mcp_proxy_adapter/commands/__init__.py +13 -4
- mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
- mcp_proxy_adapter/commands/base.py +61 -30
- mcp_proxy_adapter/commands/builtin_commands.py +89 -0
- mcp_proxy_adapter/commands/catalog_manager.py +838 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
- mcp_proxy_adapter/commands/command_registry.py +705 -345
- mcp_proxy_adapter/commands/dependency_manager.py +245 -0
- mcp_proxy_adapter/commands/health_command.py +7 -0
- mcp_proxy_adapter/commands/hooks.py +200 -167
- mcp_proxy_adapter/commands/key_management_command.py +506 -0
- mcp_proxy_adapter/commands/load_command.py +176 -0
- mcp_proxy_adapter/commands/plugins_command.py +235 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +268 -0
- mcp_proxy_adapter/commands/reload_command.py +48 -50
- mcp_proxy_adapter/commands/result.py +1 -0
- mcp_proxy_adapter/commands/roles_management_command.py +697 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +483 -0
- mcp_proxy_adapter/commands/token_management_command.py +529 -0
- mcp_proxy_adapter/commands/transport_management_command.py +144 -0
- mcp_proxy_adapter/commands/unload_command.py +158 -0
- mcp_proxy_adapter/config.py +99 -2
- mcp_proxy_adapter/core/auth_validator.py +606 -0
- mcp_proxy_adapter/core/certificate_utils.py +827 -0
- mcp_proxy_adapter/core/config_converter.py +405 -0
- mcp_proxy_adapter/core/config_validator.py +218 -0
- mcp_proxy_adapter/core/logging.py +11 -0
- mcp_proxy_adapter/core/protocol_manager.py +226 -0
- mcp_proxy_adapter/core/proxy_registration.py +270 -0
- mcp_proxy_adapter/core/role_utils.py +426 -0
- mcp_proxy_adapter/core/security_adapter.py +373 -0
- mcp_proxy_adapter/core/security_factory.py +239 -0
- mcp_proxy_adapter/core/settings.py +1 -0
- mcp_proxy_adapter/core/ssl_utils.py +233 -0
- mcp_proxy_adapter/core/transport_manager.py +292 -0
- mcp_proxy_adapter/custom_openapi.py +22 -11
- mcp_proxy_adapter/examples/basic_server/config.json +58 -23
- mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +54 -0
- mcp_proxy_adapter/examples/basic_server/config_http.json +70 -0
- mcp_proxy_adapter/examples/basic_server/config_http_only.json +52 -0
- mcp_proxy_adapter/examples/basic_server/config_https.json +58 -0
- mcp_proxy_adapter/examples/basic_server/config_mtls.json +58 -0
- mcp_proxy_adapter/examples/basic_server/config_ssl.json +46 -0
- mcp_proxy_adapter/examples/basic_server/server.py +17 -1
- mcp_proxy_adapter/examples/custom_commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +339 -23
- mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +105 -0
- mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +129 -0
- mcp_proxy_adapter/examples/custom_commands/config.json +97 -41
- mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_https_only.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/full_help_response.json +1 -0
- mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +629 -0
- mcp_proxy_adapter/examples/custom_commands/get_openapi.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +129 -0
- mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +278 -0
- mcp_proxy_adapter/examples/custom_commands/server.py +92 -63
- mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +75 -0
- mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +299 -0
- mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +278 -0
- mcp_proxy_adapter/examples/custom_commands/test_openapi.py +27 -0
- mcp_proxy_adapter/examples/custom_commands/test_registry.py +23 -0
- mcp_proxy_adapter/examples/custom_commands/test_simple.py +19 -0
- mcp_proxy_adapter/examples/custom_project_example/README.md +103 -0
- mcp_proxy_adapter/examples/custom_project_example/README_EN.md +103 -0
- mcp_proxy_adapter/examples/simple_custom_commands/README.md +149 -0
- mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +149 -0
- mcp_proxy_adapter/main.py +175 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/tests/unit/test_config.py +53 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.0.0.dist-info/RECORD +179 -0
- mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
- mcp_proxy_adapter-4.1.0.dist-info/RECORD +0 -110
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,226 @@
|
|
1
|
+
"""
|
2
|
+
Protocol management module for MCP Proxy Adapter.
|
3
|
+
|
4
|
+
This module provides functionality for managing and validating protocol configurations,
|
5
|
+
including HTTP, HTTPS, and MTLS protocols with their respective ports.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import ssl
|
9
|
+
from typing import Dict, List, Optional, Tuple, Union
|
10
|
+
from urllib.parse import urlparse
|
11
|
+
|
12
|
+
from mcp_proxy_adapter.config import config
|
13
|
+
from mcp_proxy_adapter.core.logging import logger
|
14
|
+
|
15
|
+
|
16
|
+
class ProtocolManager:
|
17
|
+
"""
|
18
|
+
Manages protocol configurations and validates protocol access.
|
19
|
+
|
20
|
+
This class handles the validation of allowed protocols and their associated ports,
|
21
|
+
ensuring that only configured protocols are accessible.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self):
|
25
|
+
"""Initialize the protocol manager."""
|
26
|
+
self.protocols_config = config.get("protocols", {})
|
27
|
+
self.enabled = self.protocols_config.get("enabled", True)
|
28
|
+
self.allowed_protocols = self.protocols_config.get("allowed_protocols", ["http"])
|
29
|
+
|
30
|
+
def is_protocol_allowed(self, protocol: str) -> bool:
|
31
|
+
"""
|
32
|
+
Check if a protocol is allowed based on configuration.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
protocol: Protocol name (http, https, mtls)
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
True if protocol is allowed, False otherwise
|
39
|
+
"""
|
40
|
+
if not self.enabled:
|
41
|
+
logger.debug("Protocol management is disabled, allowing all protocols")
|
42
|
+
return True
|
43
|
+
|
44
|
+
protocol_lower = protocol.lower()
|
45
|
+
is_allowed = protocol_lower in self.allowed_protocols
|
46
|
+
|
47
|
+
logger.debug(f"Protocol '{protocol}' allowed: {is_allowed}")
|
48
|
+
return is_allowed
|
49
|
+
|
50
|
+
def get_protocol_port(self, protocol: str) -> Optional[int]:
|
51
|
+
"""
|
52
|
+
Get the configured port for a specific protocol.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
protocol: Protocol name (http, https, mtls)
|
56
|
+
|
57
|
+
Returns:
|
58
|
+
Port number if configured, None otherwise
|
59
|
+
"""
|
60
|
+
protocol_lower = protocol.lower()
|
61
|
+
protocol_config = self.protocols_config.get(protocol_lower, {})
|
62
|
+
|
63
|
+
if not protocol_config.get("enabled", False):
|
64
|
+
logger.debug(f"Protocol '{protocol}' is not enabled")
|
65
|
+
return None
|
66
|
+
|
67
|
+
port = protocol_config.get("port")
|
68
|
+
logger.debug(f"Protocol '{protocol}' port: {port}")
|
69
|
+
return port
|
70
|
+
|
71
|
+
def get_allowed_protocols(self) -> List[str]:
|
72
|
+
"""
|
73
|
+
Get list of all allowed protocols.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
List of allowed protocol names
|
77
|
+
"""
|
78
|
+
return self.allowed_protocols.copy()
|
79
|
+
|
80
|
+
def get_protocol_config(self, protocol: str) -> Dict:
|
81
|
+
"""
|
82
|
+
Get full configuration for a specific protocol.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
protocol: Protocol name (http, https, mtls)
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
Protocol configuration dictionary
|
89
|
+
"""
|
90
|
+
protocol_lower = protocol.lower()
|
91
|
+
return self.protocols_config.get(protocol_lower, {}).copy()
|
92
|
+
|
93
|
+
def validate_url_protocol(self, url: str) -> Tuple[bool, Optional[str]]:
|
94
|
+
"""
|
95
|
+
Validate if the URL protocol is allowed.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
url: URL to validate
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
Tuple of (is_allowed, error_message)
|
102
|
+
"""
|
103
|
+
try:
|
104
|
+
parsed = urlparse(url)
|
105
|
+
protocol = parsed.scheme.lower()
|
106
|
+
|
107
|
+
if not protocol:
|
108
|
+
return False, "No protocol specified in URL"
|
109
|
+
|
110
|
+
if not self.is_protocol_allowed(protocol):
|
111
|
+
return False, f"Protocol '{protocol}' is not allowed. Allowed protocols: {self.allowed_protocols}"
|
112
|
+
|
113
|
+
return True, None
|
114
|
+
|
115
|
+
except Exception as e:
|
116
|
+
return False, f"Invalid URL format: {str(e)}"
|
117
|
+
|
118
|
+
def get_ssl_context_for_protocol(self, protocol: str) -> Optional[ssl.SSLContext]:
|
119
|
+
"""
|
120
|
+
Get SSL context for HTTPS or MTLS protocol.
|
121
|
+
|
122
|
+
Args:
|
123
|
+
protocol: Protocol name (https, mtls)
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
SSL context if protocol requires SSL, None otherwise
|
127
|
+
"""
|
128
|
+
if protocol.lower() not in ["https", "mtls"]:
|
129
|
+
return None
|
130
|
+
|
131
|
+
ssl_config = config.get("ssl", {})
|
132
|
+
|
133
|
+
if not ssl_config.get("enabled", False):
|
134
|
+
logger.warning(f"SSL required for protocol '{protocol}' but SSL is disabled")
|
135
|
+
return None
|
136
|
+
|
137
|
+
cert_file = ssl_config.get("cert_file")
|
138
|
+
key_file = ssl_config.get("key_file")
|
139
|
+
|
140
|
+
if not cert_file or not key_file:
|
141
|
+
logger.warning(f"SSL required for protocol '{protocol}' but certificate files not configured")
|
142
|
+
return None
|
143
|
+
|
144
|
+
try:
|
145
|
+
from mcp_proxy_adapter.core.ssl_utils import SSLUtils
|
146
|
+
|
147
|
+
ssl_context = SSLUtils.create_ssl_context(
|
148
|
+
cert_file=cert_file,
|
149
|
+
key_file=key_file,
|
150
|
+
ca_cert=ssl_config.get("ca_cert"),
|
151
|
+
verify_client=protocol.lower() == "mtls" or ssl_config.get("verify_client", False),
|
152
|
+
cipher_suites=ssl_config.get("cipher_suites", []),
|
153
|
+
min_tls_version=ssl_config.get("min_tls_version", "1.2"),
|
154
|
+
max_tls_version=ssl_config.get("max_tls_version", "1.3")
|
155
|
+
)
|
156
|
+
|
157
|
+
logger.info(f"SSL context created for protocol '{protocol}'")
|
158
|
+
return ssl_context
|
159
|
+
|
160
|
+
except Exception as e:
|
161
|
+
logger.error(f"Failed to create SSL context for protocol '{protocol}': {e}")
|
162
|
+
return None
|
163
|
+
|
164
|
+
def get_protocol_info(self) -> Dict[str, Dict]:
|
165
|
+
"""
|
166
|
+
Get information about all configured protocols.
|
167
|
+
|
168
|
+
Returns:
|
169
|
+
Dictionary with protocol information
|
170
|
+
"""
|
171
|
+
info = {}
|
172
|
+
|
173
|
+
for protocol in ["http", "https", "mtls"]:
|
174
|
+
protocol_config = self.get_protocol_config(protocol)
|
175
|
+
info[protocol] = {
|
176
|
+
"enabled": protocol_config.get("enabled", False),
|
177
|
+
"allowed": self.is_protocol_allowed(protocol),
|
178
|
+
"port": protocol_config.get("port"),
|
179
|
+
"requires_ssl": protocol in ["https", "mtls"],
|
180
|
+
"ssl_context_available": self.get_ssl_context_for_protocol(protocol) is not None
|
181
|
+
}
|
182
|
+
|
183
|
+
return info
|
184
|
+
|
185
|
+
def validate_protocol_configuration(self) -> List[str]:
|
186
|
+
"""
|
187
|
+
Validate the current protocol configuration.
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
List of validation errors (empty if configuration is valid)
|
191
|
+
"""
|
192
|
+
errors = []
|
193
|
+
|
194
|
+
if not self.enabled:
|
195
|
+
return errors
|
196
|
+
|
197
|
+
# Check if allowed protocols are configured
|
198
|
+
for protocol in self.allowed_protocols:
|
199
|
+
if protocol not in ["http", "https", "mtls"]:
|
200
|
+
errors.append(f"Unknown protocol '{protocol}' in allowed_protocols")
|
201
|
+
continue
|
202
|
+
|
203
|
+
protocol_config = self.get_protocol_config(protocol)
|
204
|
+
|
205
|
+
if not protocol_config.get("enabled", False):
|
206
|
+
errors.append(f"Protocol '{protocol}' is in allowed_protocols but not enabled")
|
207
|
+
continue
|
208
|
+
|
209
|
+
port = protocol_config.get("port")
|
210
|
+
if not port:
|
211
|
+
errors.append(f"Protocol '{protocol}' is enabled but no port configured")
|
212
|
+
continue
|
213
|
+
|
214
|
+
# Check SSL requirements
|
215
|
+
if protocol in ["https", "mtls"]:
|
216
|
+
ssl_config = config.get("ssl", {})
|
217
|
+
if not ssl_config.get("enabled", False):
|
218
|
+
errors.append(f"Protocol '{protocol}' requires SSL but SSL is disabled")
|
219
|
+
elif not ssl_config.get("cert_file") or not ssl_config.get("key_file"):
|
220
|
+
errors.append(f"Protocol '{protocol}' requires SSL but certificate files not configured")
|
221
|
+
|
222
|
+
return errors
|
223
|
+
|
224
|
+
|
225
|
+
# Global protocol manager instance
|
226
|
+
protocol_manager = ProtocolManager()
|
@@ -0,0 +1,270 @@
|
|
1
|
+
"""
|
2
|
+
Module for proxy registration functionality.
|
3
|
+
|
4
|
+
This module handles automatic registration and unregistration of the server
|
5
|
+
with the MCP proxy server during startup and shutdown.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import json
|
10
|
+
import time
|
11
|
+
from typing import Dict, Any, Optional, Tuple
|
12
|
+
from urllib.parse import urljoin
|
13
|
+
|
14
|
+
import aiohttp
|
15
|
+
import requests
|
16
|
+
from requests.exceptions import RequestException
|
17
|
+
|
18
|
+
from mcp_proxy_adapter.config import config
|
19
|
+
from mcp_proxy_adapter.core.logging import logger
|
20
|
+
|
21
|
+
|
22
|
+
class ProxyRegistrationError(Exception):
|
23
|
+
"""Exception raised when proxy registration fails."""
|
24
|
+
pass
|
25
|
+
|
26
|
+
|
27
|
+
class ProxyRegistrationManager:
|
28
|
+
"""
|
29
|
+
Manager for proxy registration functionality.
|
30
|
+
|
31
|
+
Handles automatic registration and unregistration of the server
|
32
|
+
with the MCP proxy server.
|
33
|
+
"""
|
34
|
+
|
35
|
+
def __init__(self):
|
36
|
+
"""Initialize the proxy registration manager."""
|
37
|
+
self.registration_config = config.get("proxy_registration", {})
|
38
|
+
self.proxy_url = self.registration_config.get("proxy_url", "http://localhost:3004")
|
39
|
+
self.server_id = self.registration_config.get("server_id", "mcp_proxy_adapter")
|
40
|
+
self.server_name = self.registration_config.get("server_name", "MCP Proxy Adapter")
|
41
|
+
self.description = self.registration_config.get("description", "JSON-RPC API for interacting with MCP Proxy")
|
42
|
+
self.timeout = self.registration_config.get("registration_timeout", 30)
|
43
|
+
self.retry_attempts = self.registration_config.get("retry_attempts", 3)
|
44
|
+
self.retry_delay = self.registration_config.get("retry_delay", 5)
|
45
|
+
self.auto_register = self.registration_config.get("auto_register_on_startup", True)
|
46
|
+
self.auto_unregister = self.registration_config.get("auto_unregister_on_shutdown", True)
|
47
|
+
|
48
|
+
self.registered = False
|
49
|
+
self.server_key: Optional[str] = None
|
50
|
+
self.server_url: Optional[str] = None
|
51
|
+
|
52
|
+
def is_enabled(self) -> bool:
|
53
|
+
"""
|
54
|
+
Check if proxy registration is enabled.
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
True if registration is enabled, False otherwise.
|
58
|
+
"""
|
59
|
+
return self.registration_config.get("enabled", False)
|
60
|
+
|
61
|
+
def set_server_url(self, server_url: str) -> None:
|
62
|
+
"""
|
63
|
+
Set the server URL for registration.
|
64
|
+
|
65
|
+
Args:
|
66
|
+
server_url: The URL where this server is accessible.
|
67
|
+
"""
|
68
|
+
self.server_url = server_url
|
69
|
+
logger.info(f"Proxy registration server URL set to: {server_url}")
|
70
|
+
|
71
|
+
async def register_server(self) -> bool:
|
72
|
+
"""
|
73
|
+
Register the server with the proxy.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
True if registration was successful, False otherwise.
|
77
|
+
"""
|
78
|
+
if not self.is_enabled():
|
79
|
+
logger.info("Proxy registration is disabled in configuration")
|
80
|
+
return False
|
81
|
+
|
82
|
+
if not self.server_url:
|
83
|
+
logger.error("Server URL not set, cannot register with proxy")
|
84
|
+
return False
|
85
|
+
|
86
|
+
registration_data = {
|
87
|
+
"server_id": self.server_id,
|
88
|
+
"server_url": self.server_url,
|
89
|
+
"server_name": self.server_name,
|
90
|
+
"description": self.description
|
91
|
+
}
|
92
|
+
|
93
|
+
logger.info(f"Attempting to register server with proxy at {self.proxy_url}")
|
94
|
+
logger.debug(f"Registration data: {registration_data}")
|
95
|
+
|
96
|
+
for attempt in range(self.retry_attempts):
|
97
|
+
try:
|
98
|
+
success, result = await self._make_registration_request(registration_data)
|
99
|
+
|
100
|
+
if success:
|
101
|
+
self.registered = True
|
102
|
+
self.server_key = result.get("server_key")
|
103
|
+
logger.info(f"✅ Successfully registered with proxy. Server key: {self.server_key}")
|
104
|
+
return True
|
105
|
+
else:
|
106
|
+
error_msg = result.get("error", {}).get("message", "Unknown error")
|
107
|
+
logger.warning(f"❌ Registration attempt {attempt + 1} failed: {error_msg}")
|
108
|
+
|
109
|
+
if attempt < self.retry_attempts - 1:
|
110
|
+
logger.info(f"Retrying in {self.retry_delay} seconds...")
|
111
|
+
await asyncio.sleep(self.retry_delay)
|
112
|
+
|
113
|
+
except Exception as e:
|
114
|
+
logger.error(f"❌ Registration attempt {attempt + 1} failed with exception: {e}")
|
115
|
+
|
116
|
+
if attempt < self.retry_attempts - 1:
|
117
|
+
logger.info(f"Retrying in {self.retry_delay} seconds...")
|
118
|
+
await asyncio.sleep(self.retry_delay)
|
119
|
+
|
120
|
+
logger.error(f"❌ Failed to register with proxy after {self.retry_attempts} attempts")
|
121
|
+
return False
|
122
|
+
|
123
|
+
async def unregister_server(self) -> bool:
|
124
|
+
"""
|
125
|
+
Unregister the server from the proxy.
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
True if unregistration was successful, False otherwise.
|
129
|
+
"""
|
130
|
+
if not self.is_enabled():
|
131
|
+
logger.info("Proxy registration is disabled, skipping unregistration")
|
132
|
+
return True
|
133
|
+
|
134
|
+
if not self.registered or not self.server_key:
|
135
|
+
logger.info("Server not registered with proxy, skipping unregistration")
|
136
|
+
return True
|
137
|
+
|
138
|
+
# Extract copy_number from server_key (format: server_id_copy_number)
|
139
|
+
try:
|
140
|
+
copy_number = int(self.server_key.split("_")[-1])
|
141
|
+
except (ValueError, IndexError):
|
142
|
+
copy_number = 1
|
143
|
+
|
144
|
+
unregistration_data = {
|
145
|
+
"server_id": self.server_id,
|
146
|
+
"copy_number": copy_number
|
147
|
+
}
|
148
|
+
|
149
|
+
logger.info(f"Attempting to unregister server from proxy at {self.proxy_url}")
|
150
|
+
logger.debug(f"Unregistration data: {unregistration_data}")
|
151
|
+
|
152
|
+
try:
|
153
|
+
success, result = await self._make_unregistration_request(unregistration_data)
|
154
|
+
|
155
|
+
if success:
|
156
|
+
unregistered = result.get("unregistered", False)
|
157
|
+
if unregistered:
|
158
|
+
logger.info("✅ Successfully unregistered from proxy")
|
159
|
+
else:
|
160
|
+
logger.warning("⚠️ Server was not found in proxy registry")
|
161
|
+
|
162
|
+
self.registered = False
|
163
|
+
self.server_key = None
|
164
|
+
return True
|
165
|
+
else:
|
166
|
+
error_msg = result.get("error", {}).get("message", "Unknown error")
|
167
|
+
logger.error(f"❌ Failed to unregister from proxy: {error_msg}")
|
168
|
+
return False
|
169
|
+
|
170
|
+
except Exception as e:
|
171
|
+
logger.error(f"❌ Unregistration failed with exception: {e}")
|
172
|
+
return False
|
173
|
+
|
174
|
+
async def _make_registration_request(self, data: Dict[str, Any]) -> Tuple[bool, Dict[str, Any]]:
|
175
|
+
"""
|
176
|
+
Make registration request to proxy.
|
177
|
+
|
178
|
+
Args:
|
179
|
+
data: Registration data.
|
180
|
+
|
181
|
+
Returns:
|
182
|
+
Tuple of (success, result).
|
183
|
+
"""
|
184
|
+
url = urljoin(self.proxy_url, "/register")
|
185
|
+
|
186
|
+
async with aiohttp.ClientSession() as session:
|
187
|
+
async with session.post(
|
188
|
+
url,
|
189
|
+
json=data,
|
190
|
+
headers={"Content-Type": "application/json"},
|
191
|
+
timeout=aiohttp.ClientTimeout(total=self.timeout)
|
192
|
+
) as response:
|
193
|
+
result = await response.json()
|
194
|
+
return response.status == 200, result
|
195
|
+
|
196
|
+
async def _make_unregistration_request(self, data: Dict[str, Any]) -> Tuple[bool, Dict[str, Any]]:
|
197
|
+
"""
|
198
|
+
Make unregistration request to proxy.
|
199
|
+
|
200
|
+
Args:
|
201
|
+
data: Unregistration data.
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
Tuple of (success, result).
|
205
|
+
"""
|
206
|
+
url = urljoin(self.proxy_url, "/unregister")
|
207
|
+
|
208
|
+
async with aiohttp.ClientSession() as session:
|
209
|
+
async with session.post(
|
210
|
+
url,
|
211
|
+
json=data,
|
212
|
+
headers={"Content-Type": "application/json"},
|
213
|
+
timeout=aiohttp.ClientTimeout(total=self.timeout)
|
214
|
+
) as response:
|
215
|
+
result = await response.json()
|
216
|
+
return response.status == 200, result
|
217
|
+
|
218
|
+
def get_registration_status(self) -> Dict[str, Any]:
|
219
|
+
"""
|
220
|
+
Get current registration status.
|
221
|
+
|
222
|
+
Returns:
|
223
|
+
Dictionary with registration status information.
|
224
|
+
"""
|
225
|
+
return {
|
226
|
+
"enabled": self.is_enabled(),
|
227
|
+
"registered": self.registered,
|
228
|
+
"server_key": self.server_key,
|
229
|
+
"server_url": self.server_url,
|
230
|
+
"proxy_url": self.proxy_url,
|
231
|
+
"server_id": self.server_id
|
232
|
+
}
|
233
|
+
|
234
|
+
|
235
|
+
# Global proxy registration manager instance
|
236
|
+
proxy_registration_manager = ProxyRegistrationManager()
|
237
|
+
|
238
|
+
|
239
|
+
async def register_with_proxy(server_url: str) -> bool:
|
240
|
+
"""
|
241
|
+
Register the server with the proxy.
|
242
|
+
|
243
|
+
Args:
|
244
|
+
server_url: The URL where this server is accessible.
|
245
|
+
|
246
|
+
Returns:
|
247
|
+
True if registration was successful, False otherwise.
|
248
|
+
"""
|
249
|
+
proxy_registration_manager.set_server_url(server_url)
|
250
|
+
return await proxy_registration_manager.register_server()
|
251
|
+
|
252
|
+
|
253
|
+
async def unregister_from_proxy() -> bool:
|
254
|
+
"""
|
255
|
+
Unregister the server from the proxy.
|
256
|
+
|
257
|
+
Returns:
|
258
|
+
True if unregistration was successful, False otherwise.
|
259
|
+
"""
|
260
|
+
return await proxy_registration_manager.unregister_server()
|
261
|
+
|
262
|
+
|
263
|
+
def get_proxy_registration_status() -> Dict[str, Any]:
|
264
|
+
"""
|
265
|
+
Get current proxy registration status.
|
266
|
+
|
267
|
+
Returns:
|
268
|
+
Dictionary with registration status information.
|
269
|
+
"""
|
270
|
+
return proxy_registration_manager.get_registration_status()
|