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
@@ -22,69 +22,89 @@ from mcp_proxy_adapter.core.settings import (
|
|
22
22
|
get_setting,
|
23
23
|
get_custom_setting_value
|
24
24
|
)
|
25
|
-
from .
|
25
|
+
from mcp_proxy_adapter.core.ssl_utils import SSLUtils
|
26
|
+
from mcp_proxy_adapter.core.transport_manager import transport_manager
|
27
|
+
from custom_settings_manager import CustomSettingsManager, get_app_name, is_feature_enabled
|
26
28
|
|
27
29
|
# Import custom commands and hooks
|
28
|
-
from
|
29
|
-
from
|
30
|
-
from
|
31
|
-
from
|
32
|
-
from
|
30
|
+
from custom_help_command import CustomHelpCommand
|
31
|
+
from custom_health_command import CustomHealthCommand
|
32
|
+
from data_transform_command import DataTransformCommand
|
33
|
+
from intercept_command import InterceptCommand
|
34
|
+
from advanced_hooks import register_advanced_hooks
|
33
35
|
|
34
36
|
# Import auto-registered commands
|
35
|
-
from
|
36
|
-
from
|
37
|
+
from auto_commands.auto_echo_command import AutoEchoCommand
|
38
|
+
from auto_commands.auto_info_command import AutoInfoCommand
|
37
39
|
|
38
40
|
# Import manual registration example
|
39
|
-
from
|
41
|
+
from manual_echo_command import ManualEchoCommand
|
40
42
|
|
41
43
|
# Import echo command
|
42
|
-
from
|
44
|
+
from echo_command import EchoCommand
|
43
45
|
|
44
46
|
# Import custom OpenAPI generator
|
45
|
-
from
|
47
|
+
from custom_openapi_generator import custom_openapi_generator
|
46
48
|
|
47
49
|
# Import command registry for manual registration
|
48
50
|
from mcp_proxy_adapter.commands.command_registry import registry
|
51
|
+
from mcp_proxy_adapter.config import config
|
52
|
+
from mcp_proxy_adapter.commands.hooks import register_custom_commands_hook
|
49
53
|
|
50
54
|
|
51
|
-
def
|
52
|
-
"""
|
55
|
+
async def initialize_commands():
|
56
|
+
"""
|
57
|
+
Initialize commands using the unified system initialization logic.
|
58
|
+
This function is used both at startup and during reload.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
Number of commands discovered.
|
62
|
+
"""
|
63
|
+
# Use the unified reload method from registry
|
64
|
+
result = await registry.reload_system()
|
65
|
+
return result["total_commands"]
|
66
|
+
|
67
|
+
|
68
|
+
def custom_commands_hook(registry):
|
69
|
+
"""Hook function for registering custom commands."""
|
53
70
|
logger = get_logger("custom_commands")
|
54
|
-
logger.info("Registering custom commands...")
|
71
|
+
logger.info("Registering custom commands via hook...")
|
55
72
|
|
56
73
|
# Get custom commands configuration from custom settings
|
57
74
|
custom_commands_config = get_custom_setting_value("custom_commands", {})
|
58
75
|
|
59
|
-
# Register echo command
|
60
|
-
registry.
|
61
|
-
|
76
|
+
# Register echo command (only if not already registered)
|
77
|
+
if not registry.command_exists("echo"):
|
78
|
+
registry.register_custom(EchoCommand)
|
79
|
+
logger.info("Registered: echo command")
|
80
|
+
else:
|
81
|
+
logger.debug("Command 'echo' is already registered, skipping")
|
62
82
|
|
63
83
|
# Register custom help command (will override built-in)
|
64
84
|
if custom_commands_config.get("help", {}).get("enabled", True):
|
65
|
-
registry.
|
85
|
+
registry.register_custom(CustomHelpCommand)
|
66
86
|
logger.info("Registered: custom help command")
|
67
87
|
|
68
88
|
# Register custom health command (will override built-in)
|
69
89
|
if custom_commands_config.get("health", {}).get("enabled", True):
|
70
|
-
registry.
|
90
|
+
registry.register_custom(CustomHealthCommand)
|
71
91
|
logger.info("Registered: custom health command")
|
72
92
|
|
73
93
|
# Register advanced demonstration commands
|
74
94
|
if custom_commands_config.get("data_transform", {}).get("enabled", True):
|
75
|
-
registry.
|
95
|
+
registry.register_custom(DataTransformCommand)
|
76
96
|
logger.info("Registered: data_transform command")
|
77
97
|
|
78
98
|
if custom_commands_config.get("intercept", {}).get("enabled", True):
|
79
|
-
registry.
|
99
|
+
registry.register_custom(InterceptCommand)
|
80
100
|
logger.info("Registered: intercept command")
|
81
101
|
|
82
102
|
# Register manually registered commands
|
83
103
|
if custom_commands_config.get("manual_echo", {}).get("enabled", True):
|
84
|
-
registry.
|
104
|
+
registry.register_custom(ManualEchoCommand)
|
85
105
|
logger.info("Registered: manual_echo command")
|
86
106
|
|
87
|
-
logger.info(f"Total commands registered: {len(registry.
|
107
|
+
logger.info(f"Total custom commands registered: {len(registry.get_commands_by_type()['custom'])}")
|
88
108
|
|
89
109
|
|
90
110
|
def setup_hooks():
|
@@ -92,27 +112,11 @@ def setup_hooks():
|
|
92
112
|
logger = get_logger("custom_commands")
|
93
113
|
logger.info("Setting up hooks...")
|
94
114
|
|
95
|
-
#
|
96
|
-
|
115
|
+
# Register custom commands hook
|
116
|
+
from mcp_proxy_adapter.commands.hooks import register_custom_commands_hook
|
117
|
+
register_custom_commands_hook(custom_commands_hook)
|
97
118
|
|
98
|
-
|
99
|
-
# register_all_hooks(hooks) # This line was removed as per the new_code, as hooks is no longer imported.
|
100
|
-
logger.info("Registered: basic hooks")
|
101
|
-
|
102
|
-
# Register advanced hooks based on configuration
|
103
|
-
if hooks_config.get("data_transform", {}).get("enabled", True):
|
104
|
-
# register_advanced_hooks(None) # Temporarily disabled for simplicity
|
105
|
-
logger.info("Registered: data transformation hooks (disabled for now)")
|
106
|
-
|
107
|
-
if hooks_config.get("intercept", {}).get("enabled", True):
|
108
|
-
logger.info("Registered: interception hooks")
|
109
|
-
|
110
|
-
logger.info("Registered: command-specific hooks")
|
111
|
-
logger.info("Registered: global hooks")
|
112
|
-
logger.info("Registered: performance monitoring hooks")
|
113
|
-
logger.info("Registered: security monitoring hooks")
|
114
|
-
logger.info("Registered: data transformation hooks")
|
115
|
-
logger.info("Registered: interception hooks")
|
119
|
+
logger.info("Registered: custom commands hook")
|
116
120
|
|
117
121
|
|
118
122
|
def main():
|
@@ -126,6 +130,8 @@ def main():
|
|
126
130
|
else:
|
127
131
|
print(f"⚠️ Configuration file not found: {config_path}")
|
128
132
|
print(" Using default configuration")
|
133
|
+
from mcp_proxy_adapter.config import config
|
134
|
+
config.load_config()
|
129
135
|
|
130
136
|
# Setup logging with configuration
|
131
137
|
setup_logging()
|
@@ -143,6 +149,16 @@ def main():
|
|
143
149
|
commands_settings = Settings.get_commands_settings()
|
144
150
|
custom_settings = Settings.get_custom_setting("custom", {})
|
145
151
|
|
152
|
+
# Load transport configuration
|
153
|
+
if not transport_manager.load_config(config.config_data):
|
154
|
+
logger.error("Failed to load transport configuration")
|
155
|
+
return
|
156
|
+
|
157
|
+
# Validate transport configuration
|
158
|
+
if not transport_manager.validate_config():
|
159
|
+
logger.error("Transport configuration validation failed")
|
160
|
+
return
|
161
|
+
|
146
162
|
# Print server header and description
|
147
163
|
print("=" * 80)
|
148
164
|
print("🔧 ADVANCED MCP PROXY ADAPTER SERVER WITH HOOKS")
|
@@ -150,12 +166,21 @@ def main():
|
|
150
166
|
print("📋 Description:")
|
151
167
|
print(f" {get_app_name()} - Advanced server with custom settings management")
|
152
168
|
print()
|
169
|
+
# Get transport info
|
170
|
+
transport_info = transport_manager.get_transport_info()
|
171
|
+
|
153
172
|
print("⚙️ Configuration:")
|
154
|
-
print(f" • Server: {server_settings['host']}:{
|
173
|
+
print(f" • Server: {server_settings['host']}:{transport_manager.get_port()}")
|
174
|
+
print(f" • Transport: {transport_info['type']}")
|
155
175
|
print(f" • Debug: {server_settings['debug']}")
|
156
176
|
print(f" • Log Level: {logging_settings['level']}")
|
157
177
|
print(f" • Log Directory: {logging_settings['log_dir']}")
|
158
178
|
print(f" • Auto Discovery: {commands_settings['auto_discovery']}")
|
179
|
+
print(f" • SSL Enabled: {transport_info['ssl_enabled']}")
|
180
|
+
if transport_info['ssl_enabled']:
|
181
|
+
ssl_config = transport_info['ssl_config']
|
182
|
+
print(f" • SSL Cert: {ssl_config.get('cert_file', 'Not specified')}")
|
183
|
+
print(f" • Client Verification: {ssl_config.get('verify_client', False)}")
|
159
184
|
print()
|
160
185
|
print("🔧 Available Commands:")
|
161
186
|
print(" • help - Custom help command (overrides built-in)")
|
@@ -163,12 +188,14 @@ def main():
|
|
163
188
|
print(" • config - Built-in config command")
|
164
189
|
print(" • reload - Built-in reload command")
|
165
190
|
print(" • settings - Built-in settings command")
|
166
|
-
print(" •
|
191
|
+
print(" • load - Built-in load command")
|
192
|
+
print(" • unload - Built-in unload command")
|
193
|
+
print(" • plugins - Built-in plugins command")
|
194
|
+
print(" • echo - Custom echo command")
|
167
195
|
print(" • data_transform - Data transformation command")
|
168
196
|
print(" • intercept - Command interception example")
|
169
197
|
print(" • manual_echo - Manually registered echo command")
|
170
|
-
print(" •
|
171
|
-
print(" • auto_info - Auto-registered info command")
|
198
|
+
print(" • test - Remote command (loaded from plugin server)")
|
172
199
|
print()
|
173
200
|
print("🎯 Features:")
|
174
201
|
print(" • Advanced JSON-RPC API")
|
@@ -186,23 +213,20 @@ def main():
|
|
186
213
|
logger.info(f"Server configuration: {server_settings}")
|
187
214
|
logger.info(f"Logging configuration: {logging_settings}")
|
188
215
|
logger.info(f"Commands configuration: {commands_settings}")
|
189
|
-
logger.info("
|
190
|
-
logger.info("
|
191
|
-
logger.info("•
|
192
|
-
logger.info("• Built-in commands:
|
216
|
+
logger.info(f"Transport configuration: {transport_info}")
|
217
|
+
logger.info("This server demonstrates custom commands with hooks and remote plugin loading:")
|
218
|
+
logger.info("• Custom commands: echo, help, health, data_transform, intercept, manual_echo")
|
219
|
+
logger.info("• Built-in commands: config, reload, settings, load, unload, plugins")
|
220
|
+
logger.info("• Remote commands: test (loaded from plugin server)")
|
193
221
|
logger.info("With advanced hooks for data transformation and command interception")
|
194
222
|
|
195
|
-
#
|
196
|
-
register_custom_commands()
|
197
|
-
|
198
|
-
# Discover auto-registered commands
|
199
|
-
logger.info("Discovering auto-registered commands...")
|
200
|
-
auto_commands_path = commands_settings.get("auto_commands_path", "mcp_proxy_adapter.examples.custom_commands.auto_commands")
|
201
|
-
registry.discover_commands(auto_commands_path)
|
202
|
-
|
203
|
-
# Setup hooks
|
223
|
+
# Setup hooks for command processing
|
204
224
|
setup_hooks()
|
205
225
|
|
226
|
+
# Initialize commands
|
227
|
+
import asyncio
|
228
|
+
asyncio.run(initialize_commands())
|
229
|
+
|
206
230
|
# Create application with settings from configuration
|
207
231
|
app = create_app(
|
208
232
|
title=get_app_name(),
|
@@ -210,12 +234,17 @@ def main():
|
|
210
234
|
version="2.1.0"
|
211
235
|
)
|
212
236
|
|
237
|
+
# Get uvicorn configuration from transport manager
|
238
|
+
uvicorn_config = transport_manager.get_uvicorn_config()
|
239
|
+
uvicorn_config["host"] = server_settings['host']
|
240
|
+
uvicorn_config["log_level"] = server_settings['log_level'].lower()
|
241
|
+
|
242
|
+
logger.info(f"Starting server with uvicorn config: {uvicorn_config}")
|
243
|
+
|
213
244
|
# Run the server with configuration settings
|
214
245
|
uvicorn.run(
|
215
246
|
app,
|
216
|
-
|
217
|
-
port=server_settings['port'],
|
218
|
-
log_level=server_settings['log_level'].lower()
|
247
|
+
**uvicorn_config
|
219
248
|
)
|
220
249
|
|
221
250
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Simple server with fixed OpenAPI generator.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import uvicorn
|
7
|
+
import asyncio
|
8
|
+
import sys
|
9
|
+
import os
|
10
|
+
from pathlib import Path
|
11
|
+
|
12
|
+
# Add current directory to path for imports
|
13
|
+
sys.path.insert(0, os.getcwd())
|
14
|
+
|
15
|
+
from fastapi import FastAPI
|
16
|
+
from mcp_proxy_adapter.custom_openapi import CustomOpenAPIGenerator
|
17
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
18
|
+
|
19
|
+
# Create FastAPI app
|
20
|
+
app = FastAPI(
|
21
|
+
title="Extended MCP Proxy Server",
|
22
|
+
description="Advanced MCP Proxy Adapter server with custom commands and hooks",
|
23
|
+
version="2.1.0"
|
24
|
+
)
|
25
|
+
|
26
|
+
async def generate_openapi_schema():
|
27
|
+
"""Generate OpenAPI schema with custom commands."""
|
28
|
+
# Initialize commands
|
29
|
+
await registry.reload_system()
|
30
|
+
|
31
|
+
# Load custom commands
|
32
|
+
custom_commands = [
|
33
|
+
"echo_command",
|
34
|
+
"custom_help_command",
|
35
|
+
"custom_health_command",
|
36
|
+
"manual_echo_command"
|
37
|
+
]
|
38
|
+
|
39
|
+
for cmd_name in custom_commands:
|
40
|
+
try:
|
41
|
+
module = __import__(cmd_name)
|
42
|
+
if hasattr(module, 'EchoCommand'):
|
43
|
+
registry.register_custom(module.EchoCommand())
|
44
|
+
elif hasattr(module, 'CustomHelpCommand'):
|
45
|
+
registry.register_custom(module.CustomHelpCommand())
|
46
|
+
elif hasattr(module, 'CustomHealthCommand'):
|
47
|
+
registry.register_custom(module.CustomHealthCommand())
|
48
|
+
elif hasattr(module, 'ManualEchoCommand'):
|
49
|
+
registry.register_custom(module.ManualEchoCommand())
|
50
|
+
except Exception as e:
|
51
|
+
print(f"Warning: Failed to load {cmd_name}: {e}")
|
52
|
+
|
53
|
+
# Generate schema
|
54
|
+
generator = CustomOpenAPIGenerator()
|
55
|
+
return generator.generate(
|
56
|
+
title="Extended MCP Proxy Server",
|
57
|
+
description="Advanced MCP Proxy Adapter server with custom commands and hooks",
|
58
|
+
version="2.1.0"
|
59
|
+
)
|
60
|
+
|
61
|
+
# Set custom OpenAPI generator
|
62
|
+
@app.on_event("startup")
|
63
|
+
async def startup_event():
|
64
|
+
"""Initialize OpenAPI schema on startup."""
|
65
|
+
app.openapi_schema = await generate_openapi_schema()
|
66
|
+
|
67
|
+
@app.get("/openapi.json")
|
68
|
+
async def get_openapi_schema():
|
69
|
+
"""Returns OpenAPI schema."""
|
70
|
+
if not hasattr(app, 'openapi_schema'):
|
71
|
+
app.openapi_schema = await generate_openapi_schema()
|
72
|
+
return app.openapi_schema
|
73
|
+
|
74
|
+
if __name__ == "__main__":
|
75
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
@@ -0,0 +1,299 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Server startup script with Proxy Connection Manager.
|
4
|
+
|
5
|
+
This script starts the server and manages proxy connection with regular
|
6
|
+
health checks and automatic re-registration.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import asyncio
|
10
|
+
import time
|
11
|
+
import sys
|
12
|
+
import os
|
13
|
+
import uvicorn
|
14
|
+
import threading
|
15
|
+
import signal
|
16
|
+
from pathlib import Path
|
17
|
+
|
18
|
+
# Add parent directories to path
|
19
|
+
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
|
20
|
+
|
21
|
+
from mcp_proxy_adapter import create_app
|
22
|
+
from mcp_proxy_adapter.core.logging import get_logger, setup_logging
|
23
|
+
from mcp_proxy_adapter.core.settings import (
|
24
|
+
Settings,
|
25
|
+
get_server_host,
|
26
|
+
get_server_port,
|
27
|
+
get_server_debug,
|
28
|
+
get_setting,
|
29
|
+
get_custom_setting_value
|
30
|
+
)
|
31
|
+
from mcp_proxy_adapter.core.ssl_utils import SSLUtils
|
32
|
+
from mcp_proxy_adapter.core.transport_manager import transport_manager
|
33
|
+
from custom_settings_manager import CustomSettingsManager, get_app_name, is_feature_enabled
|
34
|
+
|
35
|
+
# Import custom commands and hooks
|
36
|
+
from custom_help_command import CustomHelpCommand
|
37
|
+
from custom_health_command import CustomHealthCommand
|
38
|
+
from data_transform_command import DataTransformCommand
|
39
|
+
from intercept_command import InterceptCommand
|
40
|
+
from advanced_hooks import register_advanced_hooks
|
41
|
+
|
42
|
+
# Import auto-registered commands
|
43
|
+
from auto_commands.auto_echo_command import AutoEchoCommand
|
44
|
+
from auto_commands.auto_info_command import AutoInfoCommand
|
45
|
+
|
46
|
+
# Import manual registration example
|
47
|
+
from manual_echo_command import ManualEchoCommand
|
48
|
+
|
49
|
+
# Import echo command
|
50
|
+
from echo_command import EchoCommand
|
51
|
+
|
52
|
+
# Import custom OpenAPI generator
|
53
|
+
from custom_openapi_generator import custom_openapi_generator
|
54
|
+
|
55
|
+
# Import command registry for manual registration
|
56
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
57
|
+
from mcp_proxy_adapter.config import config
|
58
|
+
from mcp_proxy_adapter.commands.hooks import register_custom_commands_hook
|
59
|
+
|
60
|
+
# Import proxy connection manager
|
61
|
+
from proxy_connection_manager import start_proxy_manager, stop_proxy_manager, get_proxy_manager_status
|
62
|
+
|
63
|
+
|
64
|
+
def custom_commands_hook(registry):
|
65
|
+
"""Hook function for registering custom commands."""
|
66
|
+
logger = get_logger("custom_commands")
|
67
|
+
logger.info("Registering custom commands via hook...")
|
68
|
+
|
69
|
+
# Get custom commands configuration from custom settings
|
70
|
+
custom_commands_config = get_custom_setting_value("custom_commands", {})
|
71
|
+
|
72
|
+
# Register echo command (only if not already registered)
|
73
|
+
if not registry.command_exists("echo"):
|
74
|
+
registry.register_custom(EchoCommand)
|
75
|
+
logger.info("Registered: echo command")
|
76
|
+
else:
|
77
|
+
logger.debug("Command 'echo' is already registered, skipping")
|
78
|
+
|
79
|
+
# Register custom help command (will override built-in)
|
80
|
+
if custom_commands_config.get("help", {}).get("enabled", True):
|
81
|
+
registry.register_custom(CustomHelpCommand)
|
82
|
+
logger.info("Registered: custom help command")
|
83
|
+
|
84
|
+
# Register custom health command (will override built-in)
|
85
|
+
if custom_commands_config.get("health", {}).get("enabled", True):
|
86
|
+
registry.register_custom(CustomHealthCommand)
|
87
|
+
logger.info("Registered: custom health command")
|
88
|
+
|
89
|
+
# Register advanced demonstration commands
|
90
|
+
if custom_commands_config.get("data_transform", {}).get("enabled", True):
|
91
|
+
registry.register_custom(DataTransformCommand)
|
92
|
+
logger.info("Registered: data_transform command")
|
93
|
+
|
94
|
+
if custom_commands_config.get("intercept", {}).get("enabled", True):
|
95
|
+
registry.register_custom(InterceptCommand)
|
96
|
+
logger.info("Registered: intercept command")
|
97
|
+
|
98
|
+
|
99
|
+
def setup_hooks():
|
100
|
+
"""Setup hooks for command processing."""
|
101
|
+
logger = get_logger("custom_commands")
|
102
|
+
logger.info("Setting up hooks...")
|
103
|
+
|
104
|
+
# Register custom commands hook
|
105
|
+
register_custom_commands_hook(custom_commands_hook)
|
106
|
+
|
107
|
+
# Note: Advanced hooks are not compatible with current API
|
108
|
+
# They will be registered automatically by the command registry
|
109
|
+
logger.info("Basic hooks setup completed")
|
110
|
+
|
111
|
+
|
112
|
+
async def initialize_commands():
|
113
|
+
"""
|
114
|
+
Initialize commands using the unified system initialization logic.
|
115
|
+
This function is used both at startup and during reload.
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
Number of commands discovered.
|
119
|
+
"""
|
120
|
+
# Use the unified reload method from registry
|
121
|
+
result = await registry.reload_system()
|
122
|
+
return result["total_commands"]
|
123
|
+
|
124
|
+
|
125
|
+
def start_server():
|
126
|
+
"""Start the server in a separate thread."""
|
127
|
+
# Initialize settings
|
128
|
+
settings = Settings()
|
129
|
+
server_settings = settings.get_server_settings()
|
130
|
+
logging_settings = settings.get_logging_settings()
|
131
|
+
commands_settings = settings.get_commands_settings()
|
132
|
+
|
133
|
+
# Setup logging - pass only the level, not the entire dict
|
134
|
+
setup_logging(logging_settings.get('level', 'INFO'))
|
135
|
+
logger = get_logger("server_startup")
|
136
|
+
|
137
|
+
# Load transport configuration
|
138
|
+
if not transport_manager.load_config(config.config_data):
|
139
|
+
logger.error("Failed to load transport configuration")
|
140
|
+
return
|
141
|
+
|
142
|
+
# Validate transport configuration
|
143
|
+
if not transport_manager.validate_config():
|
144
|
+
logger.error("Transport configuration validation failed")
|
145
|
+
return
|
146
|
+
|
147
|
+
# Print server header and description
|
148
|
+
print("=" * 80)
|
149
|
+
print("🔧 ADVANCED MCP PROXY ADAPTER SERVER WITH PROXY MANAGER")
|
150
|
+
print("=" * 80)
|
151
|
+
print("📋 Description:")
|
152
|
+
print(f" {get_app_name()} - Advanced server with proxy connection management")
|
153
|
+
print()
|
154
|
+
|
155
|
+
# Get transport info
|
156
|
+
transport_info = transport_manager.get_transport_info()
|
157
|
+
|
158
|
+
print("⚙️ Configuration:")
|
159
|
+
print(f" • Server: {server_settings['host']}:{transport_manager.get_port()}")
|
160
|
+
print(f" • Transport: {transport_info['type']}")
|
161
|
+
print(f" • Debug: {server_settings['debug']}")
|
162
|
+
print(f" • Log Level: {logging_settings.get('level', 'INFO')}")
|
163
|
+
print(f" • Log Directory: {logging_settings.get('log_dir', './logs')}")
|
164
|
+
print(f" • Auto Discovery: {commands_settings['auto_discovery']}")
|
165
|
+
print(f" • SSL Enabled: {transport_info['ssl_enabled']}")
|
166
|
+
if transport_info['ssl_enabled']:
|
167
|
+
ssl_config = transport_info['ssl_config']
|
168
|
+
print(f" • SSL Cert: {ssl_config.get('cert_file', 'Not specified')}")
|
169
|
+
print(f" • Client Verification: {ssl_config.get('verify_client', False)}")
|
170
|
+
print()
|
171
|
+
print("🔧 Available Commands:")
|
172
|
+
print(" • help - Custom help command (overrides built-in)")
|
173
|
+
print(" • health - Custom health command (overrides built-in)")
|
174
|
+
print(" • config - Built-in config command")
|
175
|
+
print(" • reload - Built-in reload command")
|
176
|
+
print(" • settings - Built-in settings command")
|
177
|
+
print(" • load - Built-in load command")
|
178
|
+
print(" • unload - Built-in unload command")
|
179
|
+
print(" • plugins - Built-in plugins command")
|
180
|
+
print(" • echo - Custom echo command")
|
181
|
+
print(" • data_transform - Data transformation command")
|
182
|
+
print(" • intercept - Command interception example")
|
183
|
+
print(" • manual_echo - Manually registered echo command")
|
184
|
+
print(" • test - Remote command (loaded from plugin server)")
|
185
|
+
print()
|
186
|
+
print("🎯 Features:")
|
187
|
+
print(" • Advanced JSON-RPC API")
|
188
|
+
print(" • Custom commands with hooks")
|
189
|
+
print(" • Data transformation hooks")
|
190
|
+
print(" • Command interception hooks")
|
191
|
+
print(" • Auto-registration and manual registration")
|
192
|
+
print(" • Custom OpenAPI schema generation")
|
193
|
+
print(" • Configuration-driven settings")
|
194
|
+
print(" • Custom settings management")
|
195
|
+
print(" • 🔄 Proxy Connection Manager with health monitoring")
|
196
|
+
print(" • 🔄 Automatic re-registration on proxy failure")
|
197
|
+
print("=" * 80)
|
198
|
+
print()
|
199
|
+
|
200
|
+
logger.info("Starting Advanced Custom Commands MCP Proxy Adapter Server with Proxy Manager...")
|
201
|
+
logger.info(f"Server configuration: {server_settings}")
|
202
|
+
logger.info(f"Logging configuration: {logging_settings}")
|
203
|
+
logger.info(f"Commands configuration: {commands_settings}")
|
204
|
+
logger.info(f"Transport configuration: {transport_info}")
|
205
|
+
|
206
|
+
# Setup hooks for command processing
|
207
|
+
setup_hooks()
|
208
|
+
|
209
|
+
# Initialize commands
|
210
|
+
asyncio.run(initialize_commands())
|
211
|
+
|
212
|
+
# Create application with settings from configuration
|
213
|
+
app = create_app(
|
214
|
+
title=get_app_name(),
|
215
|
+
description="Advanced MCP Proxy Adapter server with proxy connection management, demonstrating hook capabilities including data transformation, command interception, conditional processing, and smart interception hooks. Features custom commands with enhanced functionality, comprehensive settings management, and robust proxy connection handling.",
|
216
|
+
version="2.2.0"
|
217
|
+
)
|
218
|
+
|
219
|
+
# Get uvicorn configuration from transport manager
|
220
|
+
uvicorn_config = transport_manager.get_uvicorn_config()
|
221
|
+
uvicorn_config["host"] = server_settings['host']
|
222
|
+
uvicorn_config["log_level"] = server_settings['log_level'].lower()
|
223
|
+
|
224
|
+
logger.info(f"Starting server with uvicorn config: {uvicorn_config}")
|
225
|
+
|
226
|
+
# Run the server with configuration settings
|
227
|
+
uvicorn.run(
|
228
|
+
app,
|
229
|
+
**uvicorn_config
|
230
|
+
)
|
231
|
+
|
232
|
+
|
233
|
+
async def start_proxy_manager_after_server():
|
234
|
+
"""
|
235
|
+
Start proxy manager after server is fully started and listening.
|
236
|
+
"""
|
237
|
+
logger = get_logger("proxy_manager_startup")
|
238
|
+
|
239
|
+
# Wait a bit for server to fully start
|
240
|
+
await asyncio.sleep(5)
|
241
|
+
|
242
|
+
logger.info("🚀 Starting Proxy Connection Manager after server startup")
|
243
|
+
|
244
|
+
# Start proxy manager
|
245
|
+
await start_proxy_manager()
|
246
|
+
|
247
|
+
logger.info("✅ Proxy Connection Manager started successfully")
|
248
|
+
|
249
|
+
|
250
|
+
def signal_handler(signum, frame):
|
251
|
+
"""Handle shutdown signals."""
|
252
|
+
print(f"\n🛑 Received signal {signum}, shutting down gracefully...")
|
253
|
+
|
254
|
+
# Stop proxy manager
|
255
|
+
asyncio.run(stop_proxy_manager())
|
256
|
+
|
257
|
+
print("✅ Graceful shutdown completed")
|
258
|
+
sys.exit(0)
|
259
|
+
|
260
|
+
|
261
|
+
def main():
|
262
|
+
"""Main function to start server and proxy manager."""
|
263
|
+
# Setup signal handlers for graceful shutdown
|
264
|
+
signal.signal(signal.SIGINT, signal_handler)
|
265
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
266
|
+
|
267
|
+
# Start server in a separate thread
|
268
|
+
server_thread = threading.Thread(target=start_server, daemon=True)
|
269
|
+
server_thread.start()
|
270
|
+
|
271
|
+
# Wait for server to start
|
272
|
+
time.sleep(8)
|
273
|
+
|
274
|
+
# Start proxy manager after server is ready
|
275
|
+
asyncio.run(start_proxy_manager_after_server())
|
276
|
+
|
277
|
+
# Keep main thread alive and monitor status
|
278
|
+
try:
|
279
|
+
while True:
|
280
|
+
# Get proxy manager status
|
281
|
+
status = get_proxy_manager_status()
|
282
|
+
|
283
|
+
if status["is_running"]:
|
284
|
+
time_since = status.get("time_since_registration", 0)
|
285
|
+
if time_since is not None:
|
286
|
+
print(f"📊 Proxy Status: Registered {time_since:.0f}s ago, "
|
287
|
+
f"attempts: {status['registration_count']}, "
|
288
|
+
f"failed: {status['failed_attempts']}")
|
289
|
+
|
290
|
+
time.sleep(30) # Print status every 30 seconds
|
291
|
+
|
292
|
+
except KeyboardInterrupt:
|
293
|
+
print("\n🛑 Server shutdown requested")
|
294
|
+
asyncio.run(stop_proxy_manager())
|
295
|
+
sys.exit(0)
|
296
|
+
|
297
|
+
|
298
|
+
if __name__ == "__main__":
|
299
|
+
main()
|