mcp-proxy-adapter 6.9.17__py3-none-any.whl → 6.9.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_proxy_adapter/api/app.py +52 -52
- mcp_proxy_adapter/api/handlers.py +5 -5
- mcp_proxy_adapter/api/middleware/__init__.py +8 -8
- mcp_proxy_adapter/api/middleware/base.py +14 -14
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +7 -7
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -9
- mcp_proxy_adapter/api/middleware/factory.py +17 -17
- mcp_proxy_adapter/api/middleware/logging.py +6 -6
- mcp_proxy_adapter/api/middleware/performance.py +3 -3
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +19 -19
- mcp_proxy_adapter/api/middleware/transport_middleware.py +3 -3
- mcp_proxy_adapter/api/middleware/unified_security.py +11 -11
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +21 -21
- mcp_proxy_adapter/api/tool_integration.py +3 -2
- mcp_proxy_adapter/api/tools.py +4 -3
- mcp_proxy_adapter/commands/auth_validation_command.py +6 -5
- mcp_proxy_adapter/commands/base.py +10 -10
- mcp_proxy_adapter/commands/builtin_commands.py +6 -6
- mcp_proxy_adapter/commands/catalog_manager.py +74 -74
- mcp_proxy_adapter/commands/cert_monitor_command.py +13 -12
- mcp_proxy_adapter/commands/certificate_management_command.py +20 -19
- mcp_proxy_adapter/commands/command_registry.py +68 -67
- mcp_proxy_adapter/commands/config_command.py +3 -1
- mcp_proxy_adapter/commands/dependency_manager.py +10 -10
- mcp_proxy_adapter/commands/help_command.py +21 -20
- mcp_proxy_adapter/commands/hooks.py +27 -27
- mcp_proxy_adapter/commands/key_management_command.py +19 -18
- mcp_proxy_adapter/commands/plugins_command.py +2 -1
- mcp_proxy_adapter/commands/protocol_management_command.py +6 -6
- mcp_proxy_adapter/commands/proxy_registration_command.py +9 -9
- mcp_proxy_adapter/commands/registration_status_command.py +4 -4
- mcp_proxy_adapter/commands/reload_command.py +5 -5
- mcp_proxy_adapter/commands/role_test_command.py +2 -1
- mcp_proxy_adapter/commands/roles_management_command.py +9 -8
- mcp_proxy_adapter/commands/security_command.py +3 -2
- mcp_proxy_adapter/commands/ssl_setup_command.py +7 -6
- mcp_proxy_adapter/commands/token_management_command.py +12 -11
- mcp_proxy_adapter/commands/transport_management_command.py +2 -2
- mcp_proxy_adapter/config.py +3 -3
- mcp_proxy_adapter/core/__init__.py +1 -1
- mcp_proxy_adapter/core/app_runner.py +3 -3
- mcp_proxy_adapter/core/auth_validator.py +9 -9
- mcp_proxy_adapter/core/certificate_utils.py +27 -27
- mcp_proxy_adapter/core/client_manager.py +13 -13
- mcp_proxy_adapter/core/client_security.py +26 -26
- mcp_proxy_adapter/core/config_converter.py +18 -18
- mcp_proxy_adapter/core/config_validator.py +5 -1
- mcp_proxy_adapter/core/crl_utils.py +22 -22
- mcp_proxy_adapter/core/logging.py +21 -13
- mcp_proxy_adapter/core/mtls_asgi.py +7 -7
- mcp_proxy_adapter/core/mtls_asgi_app.py +9 -9
- mcp_proxy_adapter/core/mtls_proxy.py +9 -9
- mcp_proxy_adapter/core/mtls_server.py +18 -18
- mcp_proxy_adapter/core/protocol_manager.py +29 -29
- mcp_proxy_adapter/core/proxy_registration.py +67 -67
- mcp_proxy_adapter/core/security_adapter.py +18 -18
- mcp_proxy_adapter/core/security_factory.py +16 -16
- mcp_proxy_adapter/core/security_integration.py +6 -6
- mcp_proxy_adapter/core/server_adapter.py +12 -12
- mcp_proxy_adapter/core/server_engine.py +17 -17
- mcp_proxy_adapter/core/signal_handler.py +12 -12
- mcp_proxy_adapter/core/ssl_utils.py +12 -12
- mcp_proxy_adapter/core/transport_manager.py +14 -14
- mcp_proxy_adapter/core/unified_config_adapter.py +6 -6
- mcp_proxy_adapter/core/utils.py +5 -5
- mcp_proxy_adapter/custom_openapi.py +7 -7
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +2 -2
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +6 -5
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +44 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +66 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +64 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +21 -21
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +6 -6
- mcp_proxy_adapter/examples/full_application/main.py +28 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +38 -38
- mcp_proxy_adapter/examples/test_framework_complete.py +35 -35
- mcp_proxy_adapter/examples/test_mcp_server.py +2 -2
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +386 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +248 -0
- mcp_proxy_adapter/main.py +3 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.17.dist-info → mcp_proxy_adapter-6.9.19.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.9.19.dist-info/RECORD +149 -0
- mcp_proxy_adapter-6.9.17.dist-info/RECORD +0 -144
- {mcp_proxy_adapter-6.9.17.dist-info → mcp_proxy_adapter-6.9.19.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.17.dist-info → mcp_proxy_adapter-6.9.19.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.9.17.dist-info → mcp_proxy_adapter-6.9.19.dist-info}/top_level.txt +0 -0
@@ -9,7 +9,7 @@ from dataclasses import dataclass
|
|
9
9
|
from enum import Enum
|
10
10
|
from pathlib import Path
|
11
11
|
|
12
|
-
from mcp_proxy_adapter.core.logging import
|
12
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
13
13
|
|
14
14
|
|
15
15
|
class TransportType(Enum):
|
@@ -72,7 +72,7 @@ class TransportManager:
|
|
72
72
|
try:
|
73
73
|
transport_type = TransportType(transport_type_str)
|
74
74
|
except ValueError:
|
75
|
-
|
75
|
+
get_global_logger().error(f"Invalid transport type: {transport_type_str}")
|
76
76
|
return False
|
77
77
|
|
78
78
|
# Get port (use default if not specified)
|
@@ -89,13 +89,13 @@ class TransportManager:
|
|
89
89
|
transport_type in [TransportType.HTTPS, TransportType.MTLS]
|
90
90
|
and not ssl_enabled
|
91
91
|
):
|
92
|
-
|
92
|
+
get_global_logger().error(
|
93
93
|
f"SSL must be enabled for transport type: {transport_type.value}"
|
94
94
|
)
|
95
95
|
return False
|
96
96
|
|
97
97
|
if transport_type == TransportType.HTTP and ssl_enabled:
|
98
|
-
|
98
|
+
get_global_logger().warning("SSL enabled for HTTP transport - this may cause issues")
|
99
99
|
|
100
100
|
# Create transport config
|
101
101
|
self._config = TransportConfig(
|
@@ -111,13 +111,13 @@ class TransportManager:
|
|
111
111
|
|
112
112
|
self._current_transport = transport_type
|
113
113
|
|
114
|
-
|
114
|
+
get_global_logger().info(
|
115
115
|
f"Transport config loaded: {transport_type.value} on port {port}"
|
116
116
|
)
|
117
117
|
return True
|
118
118
|
|
119
119
|
except Exception as e:
|
120
|
-
|
120
|
+
get_global_logger().error(f"Failed to load transport config: {e}")
|
121
121
|
return False
|
122
122
|
|
123
123
|
def get_transport_type(self) -> Optional[TransportType]:
|
@@ -220,17 +220,17 @@ class TransportManager:
|
|
220
220
|
True if configuration is valid, False otherwise
|
221
221
|
"""
|
222
222
|
if not self._config:
|
223
|
-
|
223
|
+
get_global_logger().error("Transport not configured")
|
224
224
|
return False
|
225
225
|
|
226
226
|
# Validate SSL requirements
|
227
227
|
if self._config.type in [TransportType.HTTPS, TransportType.MTLS]:
|
228
228
|
if not self._config.ssl_enabled:
|
229
|
-
|
229
|
+
get_global_logger().error(f"SSL must be enabled for {self._config.type.value}")
|
230
230
|
return False
|
231
231
|
|
232
232
|
if not self._config.cert_file or not self._config.key_file:
|
233
|
-
|
233
|
+
get_global_logger().error(
|
234
234
|
f"SSL certificate and key required for {self._config.type.value}"
|
235
235
|
)
|
236
236
|
return False
|
@@ -242,12 +242,12 @@ class TransportManager:
|
|
242
242
|
# Validate MTLS requirements
|
243
243
|
if self._config.type == TransportType.MTLS:
|
244
244
|
if not self._config.verify_client:
|
245
|
-
|
245
|
+
get_global_logger().warning("MTLS transport should have client verification enabled")
|
246
246
|
|
247
247
|
if not self._config.ca_cert:
|
248
|
-
|
248
|
+
get_global_logger().warning("CA certificate recommended for MTLS transport")
|
249
249
|
|
250
|
-
|
250
|
+
get_global_logger().info(f"Transport configuration validated: {self._config.type.value}")
|
251
251
|
return True
|
252
252
|
|
253
253
|
def validate_ssl_files(self) -> bool:
|
@@ -270,10 +270,10 @@ class TransportManager:
|
|
270
270
|
|
271
271
|
for file_path in files_to_check:
|
272
272
|
if not Path(file_path).exists():
|
273
|
-
|
273
|
+
get_global_logger().error(f"SSL file not found: {file_path}")
|
274
274
|
return False
|
275
275
|
|
276
|
-
|
276
|
+
get_global_logger().info(f"All SSL files validated successfully: {files_to_check}")
|
277
277
|
return True
|
278
278
|
|
279
279
|
def get_hypercorn_config(self) -> Dict[str, Any]:
|
@@ -33,7 +33,7 @@ except ImportError:
|
|
33
33
|
PermissionConfig = None
|
34
34
|
RateLimitConfig = None
|
35
35
|
|
36
|
-
from mcp_proxy_adapter.core.logging import
|
36
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
37
37
|
|
38
38
|
|
39
39
|
@dataclass
|
@@ -84,7 +84,7 @@ class UnifiedConfigAdapter:
|
|
84
84
|
SecurityConfig instance or None if conversion failed
|
85
85
|
"""
|
86
86
|
if not SECURITY_FRAMEWORK_AVAILABLE:
|
87
|
-
|
87
|
+
get_global_logger().error(
|
88
88
|
"mcp_security_framework not available, cannot convert configuration"
|
89
89
|
)
|
90
90
|
return None
|
@@ -93,7 +93,7 @@ class UnifiedConfigAdapter:
|
|
93
93
|
# Validate configuration first
|
94
94
|
validation_result = self.validate_configuration(config)
|
95
95
|
if not validation_result.is_valid:
|
96
|
-
|
96
|
+
get_global_logger().error(
|
97
97
|
f"Configuration validation failed: {validation_result.errors}"
|
98
98
|
)
|
99
99
|
return None
|
@@ -112,11 +112,11 @@ class UnifiedConfigAdapter:
|
|
112
112
|
rate_limit=rate_limit_config,
|
113
113
|
)
|
114
114
|
|
115
|
-
|
115
|
+
get_global_logger().info("Configuration successfully converted to SecurityConfig")
|
116
116
|
return security_config
|
117
117
|
|
118
118
|
except Exception as e:
|
119
|
-
|
119
|
+
get_global_logger().error(f"Failed to convert configuration: {e}")
|
120
120
|
return None
|
121
121
|
|
122
122
|
def validate_configuration(self, config: Dict[str, Any]) -> ValidationResult:
|
@@ -569,7 +569,7 @@ class UnifiedConfigAdapter:
|
|
569
569
|
"enabled": migrated_config["rate_limit_enabled"]
|
570
570
|
}
|
571
571
|
|
572
|
-
|
572
|
+
get_global_logger().info("Legacy configuration migrated to new format")
|
573
573
|
return migrated_config
|
574
574
|
|
575
575
|
def get_default_config(self) -> Dict[str, Any]:
|
mcp_proxy_adapter/core/utils.py
CHANGED
@@ -12,7 +12,7 @@ import uuid
|
|
12
12
|
from datetime import datetime, timezone
|
13
13
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
14
14
|
|
15
|
-
from mcp_proxy_adapter.core.logging import
|
15
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
16
16
|
|
17
17
|
|
18
18
|
def generate_id() -> str:
|
@@ -80,7 +80,7 @@ def safe_json_loads(s: str, default: Any = None) -> Any:
|
|
80
80
|
try:
|
81
81
|
return json.loads(s)
|
82
82
|
except Exception as e:
|
83
|
-
|
83
|
+
get_global_logger().error(f"Error parsing JSON: {e}")
|
84
84
|
return default
|
85
85
|
|
86
86
|
|
@@ -99,7 +99,7 @@ def safe_json_dumps(obj: Any, default: str = "{}", indent: Optional[int] = None)
|
|
99
99
|
try:
|
100
100
|
return json.dumps(obj, ensure_ascii=False, indent=indent)
|
101
101
|
except Exception as e:
|
102
|
-
|
102
|
+
get_global_logger().error(f"Error serializing to JSON: {e}")
|
103
103
|
return default
|
104
104
|
|
105
105
|
|
@@ -137,7 +137,7 @@ def ensure_directory(path: str) -> bool:
|
|
137
137
|
os.makedirs(path, exist_ok=True)
|
138
138
|
return True
|
139
139
|
except Exception as e:
|
140
|
-
|
140
|
+
get_global_logger().error(f"Error creating directory {path}: {e}")
|
141
141
|
return False
|
142
142
|
|
143
143
|
|
@@ -159,7 +159,7 @@ def check_port_availability(host: str, port: int, timeout: float = 1.0) -> bool:
|
|
159
159
|
result = sock.connect_ex((host, port))
|
160
160
|
return result != 0 # True if connection failed (port is free)
|
161
161
|
except Exception as e:
|
162
|
-
|
162
|
+
get_global_logger().warning(f"Error checking port {port} on {host}: {e}")
|
163
163
|
return True # Assume port is available if check fails
|
164
164
|
|
165
165
|
|
@@ -12,7 +12,7 @@ from fastapi.openapi.utils import get_openapi
|
|
12
12
|
|
13
13
|
from mcp_proxy_adapter.commands.command_registry import registry
|
14
14
|
from mcp_proxy_adapter.commands.base import Command
|
15
|
-
from mcp_proxy_adapter.core.logging import
|
15
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
16
16
|
|
17
17
|
|
18
18
|
class CustomOpenAPIGenerator:
|
@@ -49,7 +49,7 @@ class CustomOpenAPIGenerator:
|
|
49
49
|
with open(self.base_schema_path, "r", encoding="utf-8") as f:
|
50
50
|
return json.load(f)
|
51
51
|
except FileNotFoundError:
|
52
|
-
|
52
|
+
get_global_logger().warning(f"Base schema file not found at {self.base_schema_path}, using fallback schema")
|
53
53
|
return self._get_fallback_schema()
|
54
54
|
|
55
55
|
def _get_fallback_schema(self) -> Dict[str, Any]:
|
@@ -406,7 +406,7 @@ class CustomOpenAPIGenerator:
|
|
406
406
|
return cmd_schema
|
407
407
|
except Exception as e:
|
408
408
|
# Return default schema if command schema generation fails
|
409
|
-
|
409
|
+
get_global_logger().warning(f"Failed to get schema for command {cmd_class.name}: {e}")
|
410
410
|
return {
|
411
411
|
"type": "object",
|
412
412
|
"title": f"Parameters for {cmd_class.name}",
|
@@ -569,7 +569,7 @@ class CustomOpenAPIGenerator:
|
|
569
569
|
# Add commands to schema
|
570
570
|
self._add_commands_to_schema(schema)
|
571
571
|
|
572
|
-
|
572
|
+
get_global_logger().debug(
|
573
573
|
f"Generated OpenAPI schema with {len(registry.get_all_commands())} commands"
|
574
574
|
)
|
575
575
|
|
@@ -620,7 +620,7 @@ def register_openapi_generator(
|
|
620
620
|
generator_func: Function that generates OpenAPI schema.
|
621
621
|
"""
|
622
622
|
_openapi_generators[name] = generator_func
|
623
|
-
|
623
|
+
get_global_logger().info(f"Registered custom OpenAPI generator: {name}")
|
624
624
|
|
625
625
|
|
626
626
|
def get_openapi_generator(name: str) -> Optional[Callable[[FastAPI], Dict[str, Any]]]:
|
@@ -669,9 +669,9 @@ def custom_openapi_with_fallback(app: FastAPI) -> Dict[str, Any]:
|
|
669
669
|
# Use the first registered generator
|
670
670
|
generator_name = list(_openapi_generators.keys())[0]
|
671
671
|
generator_func = _openapi_generators[generator_name]
|
672
|
-
|
672
|
+
get_global_logger().debug(f"Using custom OpenAPI generator: {generator_name}")
|
673
673
|
return generator_func(app)
|
674
674
|
|
675
675
|
# Fall back to default generator
|
676
|
-
|
676
|
+
get_global_logger().debug("Using default OpenAPI generator")
|
677
677
|
return custom_openapi(app)
|
@@ -63,7 +63,7 @@ def create_cert_manager_patch():
|
|
63
63
|
- )
|
64
64
|
+ # BUGFIX: Skip CA path validation if in CA creation mode
|
65
65
|
+ if self.config.ca_creation_mode:
|
66
|
-
+ self.
|
66
|
+
+ self.get_global_logger().info("CA creation mode enabled, skipping CA path validation")
|
67
67
|
+ return
|
68
68
|
+
|
69
69
|
+ if not self.config.ca_cert_path:
|
@@ -110,7 +110,7 @@ def test_fixed_cert_manager():
|
|
110
110
|
|
111
111
|
# BUGFIX: Skip CA path validation if in CA creation mode
|
112
112
|
if self.config.ca_creation_mode:
|
113
|
-
self.
|
113
|
+
self.get_global_logger().info("CA creation mode enabled, skipping CA path validation")
|
114
114
|
return
|
115
115
|
|
116
116
|
if not self.config.ca_cert_path:
|
@@ -1,7 +1,8 @@
|
|
1
|
-
"""Full Application Commands.
|
2
|
-
|
3
|
-
Custom command implementations for the full application example.
|
4
1
|
"""
|
2
|
+
Commands package for full application example.
|
3
|
+
"""
|
4
|
+
from .echo_command import EchoCommand
|
5
|
+
from .list_command import ListCommand
|
6
|
+
from .help_command import HelpCommand
|
5
7
|
|
6
|
-
|
7
|
-
from .dynamic_calculator_command import DynamicCalculatorCommand
|
8
|
+
__all__ = ["EchoCommand", "ListCommand", "HelpCommand"]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""
|
2
|
+
Echo command implementation.
|
3
|
+
"""
|
4
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
5
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError
|
6
|
+
|
7
|
+
|
8
|
+
class EchoCommand(BaseCommand):
|
9
|
+
"""Echo command that returns the input message."""
|
10
|
+
|
11
|
+
def __init__(self):
|
12
|
+
super().__init__()
|
13
|
+
self.name = "echo"
|
14
|
+
self.description = "Echo command that returns the input message"
|
15
|
+
self.version = "1.0.0"
|
16
|
+
|
17
|
+
def get_schema(self):
|
18
|
+
"""Get command schema."""
|
19
|
+
return {
|
20
|
+
"type": "object",
|
21
|
+
"properties": {
|
22
|
+
"message": {
|
23
|
+
"type": "string",
|
24
|
+
"description": "Message to echo back"
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"required": ["message"]
|
28
|
+
}
|
29
|
+
|
30
|
+
async def execute(self, params: dict) -> dict:
|
31
|
+
"""Execute echo command."""
|
32
|
+
try:
|
33
|
+
message = params.get("message", "")
|
34
|
+
return {
|
35
|
+
"echo": message,
|
36
|
+
"timestamp": self._get_timestamp()
|
37
|
+
}
|
38
|
+
except Exception as e:
|
39
|
+
raise MicroserviceError(f"Echo command failed: {str(e)}")
|
40
|
+
|
41
|
+
def _get_timestamp(self):
|
42
|
+
"""Get current timestamp."""
|
43
|
+
import time
|
44
|
+
return time.time()
|
@@ -0,0 +1,66 @@
|
|
1
|
+
"""
|
2
|
+
Help command implementation.
|
3
|
+
"""
|
4
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
5
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError
|
6
|
+
|
7
|
+
|
8
|
+
class HelpCommand(BaseCommand):
|
9
|
+
"""Help command that provides usage information."""
|
10
|
+
|
11
|
+
def __init__(self):
|
12
|
+
super().__init__()
|
13
|
+
self.name = "help"
|
14
|
+
self.description = "Get help information"
|
15
|
+
self.version = "1.0.0"
|
16
|
+
|
17
|
+
def get_schema(self):
|
18
|
+
"""Get command schema."""
|
19
|
+
return {
|
20
|
+
"type": "object",
|
21
|
+
"properties": {
|
22
|
+
"command": {
|
23
|
+
"type": "string",
|
24
|
+
"description": "Command name to get help for (optional)"
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"required": []
|
28
|
+
}
|
29
|
+
|
30
|
+
async def execute(self, params: dict) -> dict:
|
31
|
+
"""Execute help command."""
|
32
|
+
try:
|
33
|
+
command = params.get("command")
|
34
|
+
|
35
|
+
if command:
|
36
|
+
# Get help for specific command
|
37
|
+
help_info = self._get_command_help(command)
|
38
|
+
return {
|
39
|
+
"command": command,
|
40
|
+
"help": help_info,
|
41
|
+
"timestamp": self._get_timestamp()
|
42
|
+
}
|
43
|
+
else:
|
44
|
+
# Get general help
|
45
|
+
return {
|
46
|
+
"help": "MCP Proxy Adapter - Available commands: echo, list, health, help",
|
47
|
+
"usage": "Use 'help' with a command name to get specific help",
|
48
|
+
"timestamp": self._get_timestamp()
|
49
|
+
}
|
50
|
+
except Exception as e:
|
51
|
+
raise MicroserviceError(f"Help command failed: {str(e)}")
|
52
|
+
|
53
|
+
def _get_command_help(self, command: str) -> str:
|
54
|
+
"""Get help for specific command."""
|
55
|
+
help_map = {
|
56
|
+
"echo": "Echo command - returns the input message. Usage: {'message': 'your message'}",
|
57
|
+
"list": "List command - returns available commands. Usage: {}",
|
58
|
+
"health": "Health command - returns server health status. Usage: {}",
|
59
|
+
"help": "Help command - provides usage information. Usage: {'command': 'command_name'} (optional)"
|
60
|
+
}
|
61
|
+
return help_map.get(command, f"No help available for command '{command}'")
|
62
|
+
|
63
|
+
def _get_timestamp(self):
|
64
|
+
"""Get current timestamp."""
|
65
|
+
import time
|
66
|
+
return time.time()
|
@@ -0,0 +1,64 @@
|
|
1
|
+
"""
|
2
|
+
List command implementation.
|
3
|
+
"""
|
4
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
5
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError
|
6
|
+
|
7
|
+
|
8
|
+
class ListCommand(BaseCommand):
|
9
|
+
"""List command that returns available commands."""
|
10
|
+
|
11
|
+
def __init__(self):
|
12
|
+
super().__init__()
|
13
|
+
self.name = "list"
|
14
|
+
self.description = "List available commands"
|
15
|
+
self.version = "1.0.0"
|
16
|
+
|
17
|
+
def get_schema(self):
|
18
|
+
"""Get command schema."""
|
19
|
+
return {
|
20
|
+
"type": "object",
|
21
|
+
"properties": {},
|
22
|
+
"required": []
|
23
|
+
}
|
24
|
+
|
25
|
+
async def execute(self, params: dict) -> dict:
|
26
|
+
"""Execute list command."""
|
27
|
+
try:
|
28
|
+
# This is a simplified list - in a real implementation,
|
29
|
+
# this would query the command registry
|
30
|
+
commands = [
|
31
|
+
{
|
32
|
+
"name": "echo",
|
33
|
+
"description": "Echo command that returns the input message",
|
34
|
+
"version": "1.0.0"
|
35
|
+
},
|
36
|
+
{
|
37
|
+
"name": "list",
|
38
|
+
"description": "List available commands",
|
39
|
+
"version": "1.0.0"
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"name": "health",
|
43
|
+
"description": "Health check command",
|
44
|
+
"version": "1.0.0"
|
45
|
+
},
|
46
|
+
{
|
47
|
+
"name": "help",
|
48
|
+
"description": "Help command",
|
49
|
+
"version": "1.0.0"
|
50
|
+
}
|
51
|
+
]
|
52
|
+
|
53
|
+
return {
|
54
|
+
"commands": commands,
|
55
|
+
"count": len(commands),
|
56
|
+
"timestamp": self._get_timestamp()
|
57
|
+
}
|
58
|
+
except Exception as e:
|
59
|
+
raise MicroserviceError(f"List command failed: {str(e)}")
|
60
|
+
|
61
|
+
def _get_timestamp(self):
|
62
|
+
"""Get current timestamp."""
|
63
|
+
import time
|
64
|
+
return time.time()
|
@@ -18,25 +18,25 @@ class ApplicationHooks:
|
|
18
18
|
@staticmethod
|
19
19
|
def on_startup():
|
20
20
|
"""Hook executed on application startup."""
|
21
|
-
|
21
|
+
get_global_logger().info("🚀 Application startup hook executed")
|
22
22
|
# Initialize application-specific resources
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
get_global_logger().info("📊 Initializing application metrics")
|
24
|
+
get_global_logger().info("🔐 Loading security configurations")
|
25
|
+
get_global_logger().info("📝 Setting up logging")
|
26
26
|
|
27
27
|
@staticmethod
|
28
28
|
def on_shutdown():
|
29
29
|
"""Hook executed on application shutdown."""
|
30
|
-
|
30
|
+
get_global_logger().info("🛑 Application shutdown hook executed")
|
31
31
|
# Cleanup application resources
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
get_global_logger().info("🧹 Cleaning up resources")
|
33
|
+
get_global_logger().info("💾 Saving application state")
|
34
|
+
get_global_logger().info("📊 Finalizing metrics")
|
35
35
|
|
36
36
|
@staticmethod
|
37
37
|
def before_request(request_data: Dict[str, Any]) -> Dict[str, Any]:
|
38
38
|
"""Hook executed before processing any request."""
|
39
|
-
|
39
|
+
get_global_logger().info(f"🔧 Application hook: before_request with data: {request_data}")
|
40
40
|
# Add request metadata
|
41
41
|
request_data["app_metadata"] = {
|
42
42
|
"request_id": f"req_{datetime.now().timestamp()}",
|
@@ -48,7 +48,7 @@ class ApplicationHooks:
|
|
48
48
|
@staticmethod
|
49
49
|
def after_request(result: Dict[str, Any]) -> Dict[str, Any]:
|
50
50
|
"""Hook executed after processing any request."""
|
51
|
-
|
51
|
+
get_global_logger().info(f"🔧 Application hook: after_request with result: {result}")
|
52
52
|
# Add response metadata
|
53
53
|
result["app_response_metadata"] = {
|
54
54
|
"processed_at": datetime.now().isoformat(),
|
@@ -60,29 +60,29 @@ class ApplicationHooks:
|
|
60
60
|
@staticmethod
|
61
61
|
def on_error(error: Exception, context: Dict[str, Any]):
|
62
62
|
"""Hook executed when an error occurs."""
|
63
|
-
|
63
|
+
get_global_logger().error(f"🔧 Application hook: on_error - {error} in context: {context}")
|
64
64
|
# Log error details
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
get_global_logger().error(f"Error type: {type(error).__name__}")
|
66
|
+
get_global_logger().error(f"Error message: {str(error)}")
|
67
|
+
get_global_logger().error(f"Context: {context}")
|
68
68
|
|
69
69
|
@staticmethod
|
70
70
|
def on_command_registered(command_name: str, command_info: Dict[str, Any]):
|
71
71
|
"""Hook executed when a command is registered."""
|
72
|
-
|
73
|
-
|
72
|
+
get_global_logger().info(f"🔧 Application hook: on_command_registered - {command_name}")
|
73
|
+
get_global_logger().info(f"Command info: {command_info}")
|
74
74
|
# Track registered commands
|
75
|
-
|
75
|
+
get_global_logger().info(f"📝 Command '{command_name}' registered successfully")
|
76
76
|
|
77
77
|
@staticmethod
|
78
78
|
def on_command_executed(command_name: str, execution_time: float, success: bool):
|
79
79
|
"""Hook executed when a command is executed."""
|
80
|
-
|
81
|
-
|
80
|
+
get_global_logger().info(f"🔧 Application hook: on_command_executed - {command_name}")
|
81
|
+
get_global_logger().info(f"Execution time: {execution_time}s, Success: {success}")
|
82
82
|
# Track command execution metrics
|
83
83
|
if success:
|
84
|
-
|
84
|
+
get_global_logger().info(
|
85
85
|
f"✅ Command '{command_name}' executed successfully in {execution_time}s"
|
86
86
|
)
|
87
87
|
else:
|
88
|
-
|
88
|
+
get_global_logger().warning(f"⚠️ Command '{command_name}' failed after {execution_time}s")
|
@@ -18,7 +18,7 @@ class BuiltinCommandHooks:
|
|
18
18
|
@staticmethod
|
19
19
|
def before_echo_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
20
20
|
"""Hook executed before echo command."""
|
21
|
-
|
21
|
+
get_global_logger().info(f"🔧 Built-in hook: before_echo_command with params: {params}")
|
22
22
|
# Add timestamp to message
|
23
23
|
if "message" in params:
|
24
24
|
timestamp = datetime.now().isoformat()
|
@@ -28,7 +28,7 @@ class BuiltinCommandHooks:
|
|
28
28
|
@staticmethod
|
29
29
|
def after_echo_command(result: Dict[str, Any]) -> Dict[str, Any]:
|
30
30
|
"""Hook executed after echo command."""
|
31
|
-
|
31
|
+
get_global_logger().info(f"🔧 Built-in hook: after_echo_command with result: {result}")
|
32
32
|
# Add hook metadata
|
33
33
|
result["hook_metadata"] = {
|
34
34
|
"hook_type": "builtin_after_echo",
|
@@ -40,7 +40,7 @@ class BuiltinCommandHooks:
|
|
40
40
|
@staticmethod
|
41
41
|
def before_health_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
42
42
|
"""Hook executed before health command."""
|
43
|
-
|
43
|
+
get_global_logger().info(f"🔧 Built-in hook: before_health_command with params: {params}")
|
44
44
|
# Add custom health check parameters
|
45
45
|
params["include_detailed_info"] = True
|
46
46
|
params["check_dependencies"] = True
|
@@ -49,7 +49,7 @@ class BuiltinCommandHooks:
|
|
49
49
|
@staticmethod
|
50
50
|
def after_health_command(result: Dict[str, Any]) -> Dict[str, Any]:
|
51
51
|
"""Hook executed after health command."""
|
52
|
-
|
52
|
+
get_global_logger().info(f"🔧 Built-in hook: after_health_command with result: {result}")
|
53
53
|
# Add custom health metrics
|
54
54
|
if "status" in result and result["status"] == "healthy":
|
55
55
|
result["custom_metrics"] = {
|
@@ -62,7 +62,7 @@ class BuiltinCommandHooks:
|
|
62
62
|
@staticmethod
|
63
63
|
def before_config_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
64
64
|
"""Hook executed before config command."""
|
65
|
-
|
65
|
+
get_global_logger().info(f"🔧 Built-in hook: before_config_command with params: {params}")
|
66
66
|
# Add configuration validation
|
67
67
|
params["validate_config"] = True
|
68
68
|
params["include_secrets"] = False
|
@@ -71,7 +71,7 @@ class BuiltinCommandHooks:
|
|
71
71
|
@staticmethod
|
72
72
|
def after_config_command(result: Dict[str, Any]) -> Dict[str, Any]:
|
73
73
|
"""Hook executed after config command."""
|
74
|
-
|
74
|
+
get_global_logger().info(f"🔧 Built-in hook: after_config_command with result: {result}")
|
75
75
|
# Add configuration metadata
|
76
76
|
result["config_metadata"] = {
|
77
77
|
"last_modified": datetime.now().isoformat(),
|
@@ -30,6 +30,7 @@ class FullApplication:
|
|
30
30
|
self.config_path = config_path
|
31
31
|
try:
|
32
32
|
self.config = Config(config_path, validate_on_load=True)
|
33
|
+
self.config.load_config() # Explicitly load the configuration
|
33
34
|
self.logger = logging.getLogger(__name__)
|
34
35
|
self.logger.info("✅ Configuration loaded and validated successfully")
|
35
36
|
except Exception as e:
|
@@ -152,5 +153,32 @@ def get_app():
|
|
152
153
|
return app
|
153
154
|
|
154
155
|
|
156
|
+
def main():
|
157
|
+
"""Main entry point."""
|
158
|
+
import argparse
|
159
|
+
|
160
|
+
parser = argparse.ArgumentParser(description="MCP Proxy Adapter Full Application")
|
161
|
+
parser.add_argument("--config", required=True, help="Path to configuration file")
|
162
|
+
parser.add_argument("--port", type=int, help="Port to run server on")
|
163
|
+
parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
|
164
|
+
|
165
|
+
args = parser.parse_args()
|
166
|
+
|
167
|
+
# Create application
|
168
|
+
app_instance = FullApplication(args.config)
|
169
|
+
|
170
|
+
# Override port if specified
|
171
|
+
if args.port:
|
172
|
+
app_instance.config.config_data["server"]["port"] = args.port
|
173
|
+
print(f"🔧 Overriding port to {args.port}")
|
174
|
+
|
175
|
+
# Override host if specified
|
176
|
+
if args.host:
|
177
|
+
app_instance.config.config_data["server"]["host"] = args.host
|
178
|
+
print(f"🔧 Overriding host to {args.host}")
|
179
|
+
|
180
|
+
# Run server
|
181
|
+
app_instance.run()
|
182
|
+
|
155
183
|
if __name__ == "__main__":
|
156
184
|
main()
|