mcp-proxy-adapter 6.1.1__py3-none-any.whl → 6.2.1__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 +27 -7
- mcp_proxy_adapter/api/app.py +18 -7
- mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
- mcp_proxy_adapter/core/app_factory.py +87 -3
- mcp_proxy_adapter/core/app_runner.py +272 -0
- mcp_proxy_adapter/core/certificate_utils.py +291 -73
- mcp_proxy_adapter/core/client.py +574 -0
- mcp_proxy_adapter/core/client_manager.py +284 -0
- mcp_proxy_adapter/core/server_adapter.py +17 -80
- mcp_proxy_adapter/core/server_engine.py +5 -99
- mcp_proxy_adapter/core/ssl_utils.py +13 -12
- mcp_proxy_adapter/core/transport_manager.py +5 -5
- mcp_proxy_adapter/examples/__init__.py +16 -0
- mcp_proxy_adapter/examples/basic_framework/__init__.py +7 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +21 -40
- mcp_proxy_adapter/examples/commands/__init__.py +5 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +260 -75
- mcp_proxy_adapter/examples/debug_request_state.py +4 -36
- mcp_proxy_adapter/examples/debug_role_chain.py +2 -49
- mcp_proxy_adapter/examples/demo_client.py +0 -66
- mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -19
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -16
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -22
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -24
- mcp_proxy_adapter/examples/full_application/main.py +65 -44
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +0 -67
- mcp_proxy_adapter/examples/generate_certificates.py +0 -15
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +204 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +3 -70
- mcp_proxy_adapter/examples/run_example.py +1 -23
- mcp_proxy_adapter/examples/run_security_tests.py +2 -60
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -53
- mcp_proxy_adapter/examples/security_test_client.py +18 -123
- mcp_proxy_adapter/examples/setup_test_environment.py +179 -0
- mcp_proxy_adapter/examples/test_config.py +148 -0
- mcp_proxy_adapter/examples/test_config_generator.py +1 -25
- mcp_proxy_adapter/examples/test_examples.py +4 -67
- mcp_proxy_adapter/examples/universal_client.py +154 -162
- mcp_proxy_adapter/main.py +51 -161
- mcp_proxy_adapter/version.py +1 -1
- mcp_proxy_adapter-6.2.1.dist-info/METADATA +676 -0
- mcp_proxy_adapter-6.2.1.dist-info/RECORD +119 -0
- mcp_proxy_adapter/docs/EN/TROUBLESHOOTING.md +0 -285
- mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +0 -285
- mcp_proxy_adapter/examples/README.md +0 -257
- mcp_proxy_adapter/examples/README_EN.md +0 -258
- mcp_proxy_adapter/examples/SECURITY_TESTING.md +0 -455
- mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +0 -37
- mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +0 -23
- mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +0 -43
- mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +0 -36
- mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +0 -29
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +0 -34
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +0 -39
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +0 -35
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +0 -45
- mcp_proxy_adapter/examples/basic_framework/roles.json +0 -21
- mcp_proxy_adapter/examples/cert_config.json +0 -9
- mcp_proxy_adapter/examples/certs/admin.crt +0 -32
- mcp_proxy_adapter/examples/certs/admin.key +0 -52
- mcp_proxy_adapter/examples/certs/admin_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/admin_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/ca_cert.pem +0 -23
- mcp_proxy_adapter/examples/certs/ca_cert.srl +0 -1
- mcp_proxy_adapter/examples/certs/ca_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/cert_config.json +0 -9
- mcp_proxy_adapter/examples/certs/client.crt +0 -32
- mcp_proxy_adapter/examples/certs/client.key +0 -52
- mcp_proxy_adapter/examples/certs/client_admin.crt +0 -32
- mcp_proxy_adapter/examples/certs/client_admin.key +0 -52
- mcp_proxy_adapter/examples/certs/client_user.crt +0 -32
- mcp_proxy_adapter/examples/certs/client_user.key +0 -52
- mcp_proxy_adapter/examples/certs/guest_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/guest_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +0 -23
- mcp_proxy_adapter/examples/certs/proxy_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/proxy_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/readonly.crt +0 -32
- mcp_proxy_adapter/examples/certs/readonly.key +0 -52
- mcp_proxy_adapter/examples/certs/readonly_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/readonly_key.pem +0 -28
- mcp_proxy_adapter/examples/certs/server.crt +0 -32
- mcp_proxy_adapter/examples/certs/server.key +0 -52
- mcp_proxy_adapter/examples/certs/server_cert.pem +0 -32
- mcp_proxy_adapter/examples/certs/server_key.pem +0 -52
- mcp_proxy_adapter/examples/certs/test_ca_ca.crt +0 -20
- mcp_proxy_adapter/examples/certs/user.crt +0 -32
- mcp_proxy_adapter/examples/certs/user.key +0 -52
- mcp_proxy_adapter/examples/certs/user_cert.pem +0 -21
- mcp_proxy_adapter/examples/certs/user_key.pem +0 -28
- mcp_proxy_adapter/examples/client_configs/api_key_client.json +0 -13
- mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +0 -13
- mcp_proxy_adapter/examples/client_configs/certificate_client.json +0 -22
- mcp_proxy_adapter/examples/client_configs/jwt_client.json +0 -15
- mcp_proxy_adapter/examples/client_configs/no_auth_client.json +0 -9
- mcp_proxy_adapter/examples/full_application/configs/http_auth.json +0 -37
- mcp_proxy_adapter/examples/full_application/configs/http_simple.json +0 -23
- mcp_proxy_adapter/examples/full_application/configs/https_auth.json +0 -39
- mcp_proxy_adapter/examples/full_application/configs/https_simple.json +0 -25
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +0 -39
- mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +0 -45
- mcp_proxy_adapter/examples/full_application/roles.json +0 -21
- mcp_proxy_adapter/examples/keys/ca_key.pem +0 -28
- mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +0 -28
- mcp_proxy_adapter/examples/keys/test_ca_ca.key +0 -28
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +0 -220
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +0 -220
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +0 -2
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +0 -1
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +0 -1
- mcp_proxy_adapter/examples/roles.json +0 -38
- mcp_proxy_adapter/examples/server_configs/config_basic_http.json +0 -204
- mcp_proxy_adapter/examples/server_configs/config_http_token.json +0 -238
- mcp_proxy_adapter/examples/server_configs/config_https.json +0 -215
- mcp_proxy_adapter/examples/server_configs/config_https_token.json +0 -231
- mcp_proxy_adapter/examples/server_configs/config_mtls.json +0 -215
- mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +0 -250
- mcp_proxy_adapter/examples/server_configs/config_simple.json +0 -46
- mcp_proxy_adapter/examples/server_configs/roles.json +0 -38
- mcp_proxy_adapter/utils/config_generator.py +0 -727
- mcp_proxy_adapter-6.1.1.dist-info/METADATA +0 -205
- mcp_proxy_adapter-6.1.1.dist-info/RECORD +0 -197
- mcp_proxy_adapter-6.1.1.dist-info/entry_points.txt +0 -2
- mcp_proxy_adapter-6.1.1.dist-info/licenses/LICENSE +0 -21
- {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.1.dist-info}/top_level.txt +0 -0
@@ -1,25 +1,18 @@
|
|
1
1
|
"""
|
2
2
|
Custom Echo Command
|
3
|
-
|
4
3
|
This module demonstrates a custom command implementation for the full application example.
|
5
|
-
|
6
4
|
Author: Vasiliy Zdanovskiy
|
7
5
|
email: vasilyvz@gmail.com
|
8
6
|
"""
|
9
|
-
|
10
7
|
from typing import Dict, Any, Optional
|
11
8
|
from mcp_proxy_adapter.commands.base import BaseCommand
|
12
9
|
from mcp_proxy_adapter.commands.result import CommandResult
|
13
|
-
|
14
|
-
|
15
10
|
class CustomEchoResult(CommandResult):
|
16
11
|
"""Result class for custom echo command."""
|
17
|
-
|
18
12
|
def __init__(self, message: str, timestamp: str, echo_count: int):
|
19
13
|
self.message = message
|
20
14
|
self.timestamp = timestamp
|
21
15
|
self.echo_count = echo_count
|
22
|
-
|
23
16
|
def to_dict(self) -> Dict[str, Any]:
|
24
17
|
"""Convert result to dictionary."""
|
25
18
|
return {
|
@@ -28,7 +21,6 @@ class CustomEchoResult(CommandResult):
|
|
28
21
|
"echo_count": self.echo_count,
|
29
22
|
"command_type": "custom_echo"
|
30
23
|
}
|
31
|
-
|
32
24
|
def get_schema(self) -> Dict[str, Any]:
|
33
25
|
"""Get result schema."""
|
34
26
|
return {
|
@@ -41,23 +33,17 @@ class CustomEchoResult(CommandResult):
|
|
41
33
|
},
|
42
34
|
"required": ["message", "timestamp", "echo_count", "command_type"]
|
43
35
|
}
|
44
|
-
|
45
|
-
|
46
36
|
class CustomEchoCommand(BaseCommand):
|
47
37
|
"""Custom echo command implementation."""
|
48
|
-
|
49
38
|
def __init__(self):
|
50
39
|
super().__init__()
|
51
40
|
self.echo_count = 0
|
52
|
-
|
53
41
|
def get_name(self) -> str:
|
54
42
|
"""Get command name."""
|
55
43
|
return "custom_echo"
|
56
|
-
|
57
44
|
def get_description(self) -> str:
|
58
45
|
"""Get command description."""
|
59
46
|
return "Custom echo command with enhanced features"
|
60
|
-
|
61
47
|
def get_schema(self) -> Dict[str, Any]:
|
62
48
|
"""Get command schema."""
|
63
49
|
return {
|
@@ -78,20 +64,15 @@ class CustomEchoCommand(BaseCommand):
|
|
78
64
|
},
|
79
65
|
"required": ["message"]
|
80
66
|
}
|
81
|
-
|
82
67
|
async def execute(self, params: Dict[str, Any]) -> CustomEchoResult:
|
83
68
|
"""Execute the custom echo command."""
|
84
69
|
message = params.get("message", "Hello from custom echo!")
|
85
70
|
repeat = min(max(params.get("repeat", 1), 1), 10)
|
86
|
-
|
87
71
|
self.echo_count += 1
|
88
|
-
|
89
72
|
from datetime import datetime
|
90
73
|
timestamp = datetime.now().isoformat()
|
91
|
-
|
92
74
|
# Repeat the message
|
93
75
|
echoed_message = " ".join([message] * repeat)
|
94
|
-
|
95
76
|
return CustomEchoResult(
|
96
77
|
message=echoed_message,
|
97
78
|
timestamp=timestamp,
|
@@ -1,25 +1,18 @@
|
|
1
1
|
"""
|
2
2
|
Dynamic Calculator Command
|
3
|
-
|
4
3
|
This module demonstrates a dynamically loaded command implementation for the full application example.
|
5
|
-
|
6
4
|
Author: Vasiliy Zdanovskiy
|
7
5
|
email: vasilyvz@gmail.com
|
8
6
|
"""
|
9
|
-
|
10
7
|
from typing import Dict, Any, Optional
|
11
8
|
from mcp_proxy_adapter.commands.base import BaseCommand
|
12
9
|
from mcp_proxy_adapter.commands.result import CommandResult
|
13
|
-
|
14
|
-
|
15
10
|
class CalculatorResult(CommandResult):
|
16
11
|
"""Result class for calculator command."""
|
17
|
-
|
18
12
|
def __init__(self, operation: str, result: float, expression: str):
|
19
13
|
self.operation = operation
|
20
14
|
self.result = result
|
21
15
|
self.expression = expression
|
22
|
-
|
23
16
|
def to_dict(self) -> Dict[str, Any]:
|
24
17
|
"""Convert result to dictionary."""
|
25
18
|
return {
|
@@ -28,7 +21,6 @@ class CalculatorResult(CommandResult):
|
|
28
21
|
"expression": self.expression,
|
29
22
|
"command_type": "dynamic_calculator"
|
30
23
|
}
|
31
|
-
|
32
24
|
def get_schema(self) -> Dict[str, Any]:
|
33
25
|
"""Get result schema."""
|
34
26
|
return {
|
@@ -41,19 +33,14 @@ class CalculatorResult(CommandResult):
|
|
41
33
|
},
|
42
34
|
"required": ["operation", "result", "expression", "command_type"]
|
43
35
|
}
|
44
|
-
|
45
|
-
|
46
36
|
class DynamicCalculatorCommand(BaseCommand):
|
47
37
|
"""Dynamic calculator command implementation."""
|
48
|
-
|
49
38
|
def get_name(self) -> str:
|
50
39
|
"""Get command name."""
|
51
40
|
return "dynamic_calculator"
|
52
|
-
|
53
41
|
def get_description(self) -> str:
|
54
42
|
"""Get command description."""
|
55
43
|
return "Dynamic calculator with basic mathematical operations"
|
56
|
-
|
57
44
|
def get_schema(self) -> Dict[str, Any]:
|
58
45
|
"""Get command schema."""
|
59
46
|
return {
|
@@ -75,13 +62,11 @@ class DynamicCalculatorCommand(BaseCommand):
|
|
75
62
|
},
|
76
63
|
"required": ["operation", "a", "b"]
|
77
64
|
}
|
78
|
-
|
79
65
|
async def execute(self, params: Dict[str, Any]) -> CalculatorResult:
|
80
66
|
"""Execute the calculator command."""
|
81
67
|
operation = params.get("operation")
|
82
68
|
a = params.get("a")
|
83
69
|
b = params.get("b")
|
84
|
-
|
85
70
|
if operation == "add":
|
86
71
|
result = a + b
|
87
72
|
expression = f"{a} + {b}"
|
@@ -98,7 +83,6 @@ class DynamicCalculatorCommand(BaseCommand):
|
|
98
83
|
expression = f"{a} / {b}"
|
99
84
|
else:
|
100
85
|
raise ValueError(f"Unknown operation: {operation}")
|
101
|
-
|
102
86
|
return CalculatorResult(
|
103
87
|
operation=operation,
|
104
88
|
result=result,
|
@@ -1,95 +1,73 @@
|
|
1
1
|
"""
|
2
2
|
Application Hooks
|
3
|
-
|
4
3
|
This module demonstrates application-level hooks in the full application example.
|
5
|
-
|
6
4
|
Author: Vasiliy Zdanovskiy
|
7
5
|
email: vasilyvz@gmail.com
|
8
6
|
"""
|
9
|
-
|
10
7
|
import logging
|
11
8
|
from typing import Dict, Any, Optional
|
12
9
|
from datetime import datetime
|
13
|
-
|
14
10
|
logger = logging.getLogger(__name__)
|
15
|
-
|
16
|
-
|
17
11
|
class ApplicationHooks:
|
18
12
|
"""Application-level hooks."""
|
19
|
-
|
20
13
|
@staticmethod
|
21
14
|
def on_startup():
|
22
15
|
"""Hook executed on application startup."""
|
23
16
|
logger.info("🚀 Application startup hook executed")
|
24
|
-
|
25
17
|
# Initialize application-specific resources
|
26
18
|
logger.info("📊 Initializing application metrics")
|
27
19
|
logger.info("🔐 Loading security configurations")
|
28
20
|
logger.info("📝 Setting up logging")
|
29
|
-
|
30
21
|
@staticmethod
|
31
22
|
def on_shutdown():
|
32
23
|
"""Hook executed on application shutdown."""
|
33
24
|
logger.info("🛑 Application shutdown hook executed")
|
34
|
-
|
35
25
|
# Cleanup application resources
|
36
26
|
logger.info("🧹 Cleaning up resources")
|
37
27
|
logger.info("💾 Saving application state")
|
38
28
|
logger.info("📊 Finalizing metrics")
|
39
|
-
|
40
29
|
@staticmethod
|
41
30
|
def before_request(request_data: Dict[str, Any]) -> Dict[str, Any]:
|
42
31
|
"""Hook executed before processing any request."""
|
43
32
|
logger.info(f"🔧 Application hook: before_request with data: {request_data}")
|
44
|
-
|
45
33
|
# Add request metadata
|
46
34
|
request_data["app_metadata"] = {
|
47
35
|
"request_id": f"req_{datetime.now().timestamp()}",
|
48
36
|
"timestamp": datetime.now().isoformat(),
|
49
37
|
"application": "full_application_example"
|
50
38
|
}
|
51
|
-
|
52
39
|
return request_data
|
53
|
-
|
54
40
|
@staticmethod
|
55
41
|
def after_request(result: Dict[str, Any]) -> Dict[str, Any]:
|
56
42
|
"""Hook executed after processing any request."""
|
57
43
|
logger.info(f"🔧 Application hook: after_request with result: {result}")
|
58
|
-
|
59
44
|
# Add response metadata
|
60
45
|
result["app_response_metadata"] = {
|
61
46
|
"processed_at": datetime.now().isoformat(),
|
62
47
|
"application": "full_application_example",
|
63
48
|
"version": "1.0.0"
|
64
49
|
}
|
65
|
-
|
66
50
|
return result
|
67
|
-
|
68
51
|
@staticmethod
|
69
52
|
def on_error(error: Exception, context: Dict[str, Any]):
|
70
53
|
"""Hook executed when an error occurs."""
|
71
54
|
logger.error(f"🔧 Application hook: on_error - {error} in context: {context}")
|
72
|
-
|
73
55
|
# Log error details
|
74
56
|
logger.error(f"Error type: {type(error).__name__}")
|
75
57
|
logger.error(f"Error message: {str(error)}")
|
76
58
|
logger.error(f"Context: {context}")
|
77
|
-
|
78
59
|
@staticmethod
|
79
60
|
def on_command_registered(command_name: str, command_info: Dict[str, Any]):
|
80
61
|
"""Hook executed when a command is registered."""
|
81
62
|
logger.info(f"🔧 Application hook: on_command_registered - {command_name}")
|
82
63
|
logger.info(f"Command info: {command_info}")
|
83
|
-
|
84
64
|
# Track registered commands
|
85
65
|
logger.info(f"📝 Command '{command_name}' registered successfully")
|
86
|
-
|
87
66
|
@staticmethod
|
88
67
|
def on_command_executed(command_name: str, execution_time: float, success: bool):
|
89
68
|
"""Hook executed when a command is executed."""
|
90
69
|
logger.info(f"🔧 Application hook: on_command_executed - {command_name}")
|
91
70
|
logger.info(f"Execution time: {execution_time}s, Success: {success}")
|
92
|
-
|
93
71
|
# Track command execution metrics
|
94
72
|
if success:
|
95
73
|
logger.info(f"✅ Command '{command_name}' executed successfully in {execution_time}s")
|
@@ -1,64 +1,47 @@
|
|
1
1
|
"""
|
2
2
|
Built-in Command Hooks
|
3
|
-
|
4
3
|
This module demonstrates hooks for built-in commands in the full application example.
|
5
|
-
|
6
4
|
Author: Vasiliy Zdanovskiy
|
7
5
|
email: vasilyvz@gmail.com
|
8
6
|
"""
|
9
|
-
|
10
7
|
import logging
|
11
8
|
from typing import Dict, Any, Optional
|
12
9
|
from datetime import datetime
|
13
|
-
|
14
10
|
logger = logging.getLogger(__name__)
|
15
|
-
|
16
|
-
|
17
11
|
class BuiltinCommandHooks:
|
18
12
|
"""Hooks for built-in commands."""
|
19
|
-
|
20
13
|
@staticmethod
|
21
14
|
def before_echo_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
22
15
|
"""Hook executed before echo command."""
|
23
16
|
logger.info(f"🔧 Built-in hook: before_echo_command with params: {params}")
|
24
|
-
|
25
17
|
# Add timestamp to message
|
26
18
|
if "message" in params:
|
27
19
|
timestamp = datetime.now().isoformat()
|
28
20
|
params["message"] = f"[{timestamp}] {params['message']}"
|
29
|
-
|
30
21
|
return params
|
31
|
-
|
32
22
|
@staticmethod
|
33
23
|
def after_echo_command(result: Dict[str, Any]) -> Dict[str, Any]:
|
34
24
|
"""Hook executed after echo command."""
|
35
25
|
logger.info(f"🔧 Built-in hook: after_echo_command with result: {result}")
|
36
|
-
|
37
26
|
# Add hook metadata
|
38
27
|
result["hook_metadata"] = {
|
39
28
|
"hook_type": "builtin_after_echo",
|
40
29
|
"timestamp": datetime.now().isoformat(),
|
41
30
|
"processed": True
|
42
31
|
}
|
43
|
-
|
44
32
|
return result
|
45
|
-
|
46
33
|
@staticmethod
|
47
34
|
def before_health_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
48
35
|
"""Hook executed before health command."""
|
49
36
|
logger.info(f"🔧 Built-in hook: before_health_command with params: {params}")
|
50
|
-
|
51
37
|
# Add custom health check parameters
|
52
38
|
params["include_detailed_info"] = True
|
53
39
|
params["check_dependencies"] = True
|
54
|
-
|
55
40
|
return params
|
56
|
-
|
57
41
|
@staticmethod
|
58
42
|
def after_health_command(result: Dict[str, Any]) -> Dict[str, Any]:
|
59
43
|
"""Hook executed after health command."""
|
60
44
|
logger.info(f"🔧 Built-in hook: after_health_command with result: {result}")
|
61
|
-
|
62
45
|
# Add custom health metrics
|
63
46
|
if "status" in result and result["status"] == "healthy":
|
64
47
|
result["custom_metrics"] = {
|
@@ -66,30 +49,23 @@ class BuiltinCommandHooks:
|
|
66
49
|
"memory_usage": "45%",
|
67
50
|
"cpu_usage": "12%"
|
68
51
|
}
|
69
|
-
|
70
52
|
return result
|
71
|
-
|
72
53
|
@staticmethod
|
73
54
|
def before_config_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
74
55
|
"""Hook executed before config command."""
|
75
56
|
logger.info(f"🔧 Built-in hook: before_config_command with params: {params}")
|
76
|
-
|
77
57
|
# Add configuration validation
|
78
58
|
params["validate_config"] = True
|
79
59
|
params["include_secrets"] = False
|
80
|
-
|
81
60
|
return params
|
82
|
-
|
83
61
|
@staticmethod
|
84
62
|
def after_config_command(result: Dict[str, Any]) -> Dict[str, Any]:
|
85
63
|
"""Hook executed after config command."""
|
86
64
|
logger.info(f"🔧 Built-in hook: after_config_command with result: {result}")
|
87
|
-
|
88
65
|
# Add configuration metadata
|
89
66
|
result["config_metadata"] = {
|
90
67
|
"last_modified": datetime.now().isoformat(),
|
91
68
|
"version": "1.0.0",
|
92
69
|
"environment": "development"
|
93
70
|
}
|
94
|
-
|
95
71
|
return result
|
@@ -1,124 +1,149 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
"""
|
3
3
|
Full Application Example
|
4
|
-
|
5
4
|
This is a complete application that demonstrates all features of MCP Proxy Adapter framework:
|
6
5
|
- Built-in commands
|
7
6
|
- Custom commands
|
8
7
|
- Dynamically loaded commands
|
9
8
|
- Built-in command hooks
|
10
9
|
- Application hooks
|
11
|
-
|
12
10
|
Author: Vasiliy Zdanovskiy
|
13
11
|
email: vasilyvz@gmail.com
|
14
12
|
"""
|
15
|
-
|
16
13
|
import sys
|
17
14
|
import argparse
|
18
15
|
import logging
|
19
16
|
from pathlib import Path
|
20
|
-
|
21
17
|
# Add the framework to the path
|
22
18
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
|
23
|
-
|
19
|
+
from mcp_proxy_adapter.core.app_factory import create_and_run_server
|
24
20
|
from mcp_proxy_adapter.api.app import create_app
|
25
21
|
from mcp_proxy_adapter.config import Config
|
26
22
|
from mcp_proxy_adapter.commands.command_registry import CommandRegistry
|
27
|
-
|
28
|
-
|
29
23
|
class FullApplication:
|
30
24
|
"""Full application example with all framework features."""
|
31
|
-
|
32
25
|
def __init__(self, config_path: str):
|
33
26
|
self.config_path = config_path
|
34
27
|
self.config = Config(config_path)
|
35
28
|
self.app = None
|
36
29
|
self.command_registry = None
|
37
|
-
|
38
30
|
# Setup logging
|
39
31
|
logging.basicConfig(level=logging.INFO)
|
40
32
|
self.logger = logging.getLogger(__name__)
|
41
|
-
|
42
33
|
def setup_hooks(self):
|
43
34
|
"""Setup application hooks."""
|
44
35
|
try:
|
45
36
|
# Import hooks
|
46
37
|
from hooks.application_hooks import ApplicationHooks
|
47
38
|
from hooks.builtin_command_hooks import BuiltinCommandHooks
|
48
|
-
|
49
39
|
# Register application hooks
|
50
40
|
self.logger.info("🔧 Setting up application hooks...")
|
51
|
-
|
52
41
|
# Register built-in command hooks
|
53
42
|
self.logger.info("🔧 Setting up built-in command hooks...")
|
54
|
-
|
55
43
|
# Note: In a real implementation, these hooks would be registered
|
56
44
|
# with the framework's hook system
|
57
45
|
self.logger.info("✅ Hooks setup completed")
|
58
|
-
|
59
46
|
except ImportError as e:
|
60
47
|
self.logger.warning(f"⚠️ Could not import hooks: {e}")
|
61
|
-
|
62
48
|
def setup_custom_commands(self):
|
63
49
|
"""Setup custom commands."""
|
64
50
|
try:
|
65
51
|
self.logger.info("🔧 Setting up custom commands...")
|
66
|
-
|
67
52
|
# Import custom commands
|
68
53
|
from commands.custom_echo_command import CustomEchoCommand
|
69
54
|
from commands.dynamic_calculator_command import DynamicCalculatorCommand
|
70
|
-
|
71
55
|
# Register custom commands
|
72
56
|
# Note: In a real implementation, these would be registered
|
73
57
|
# with the framework's command registry
|
74
58
|
self.logger.info("✅ Custom commands setup completed")
|
75
|
-
|
76
59
|
except ImportError as e:
|
77
60
|
self.logger.warning(f"⚠️ Could not import custom commands: {e}")
|
78
|
-
|
61
|
+
def setup_proxy_endpoints(self):
|
62
|
+
"""Setup proxy registration endpoints."""
|
63
|
+
try:
|
64
|
+
self.logger.info("🔧 Setting up proxy endpoints...")
|
65
|
+
# Import proxy endpoints
|
66
|
+
from proxy_endpoints import router as proxy_router
|
67
|
+
# Add proxy router to the application
|
68
|
+
self.app.include_router(proxy_router)
|
69
|
+
self.logger.info("✅ Proxy endpoints setup completed")
|
70
|
+
except ImportError as e:
|
71
|
+
self.logger.warning(f"⚠️ Could not import proxy endpoints: {e}")
|
79
72
|
def create_application(self):
|
80
73
|
"""Create the FastAPI application."""
|
81
74
|
self.logger.info("🔧 Creating application...")
|
82
|
-
|
83
75
|
# Setup hooks and commands before creating app
|
84
76
|
self.setup_hooks()
|
85
77
|
self.setup_custom_commands()
|
86
|
-
|
87
78
|
# Create application with configuration
|
88
79
|
self.app = create_app(app_config=self.config)
|
89
|
-
|
80
|
+
# Setup proxy endpoints after app creation
|
81
|
+
self.setup_proxy_endpoints()
|
90
82
|
self.logger.info("✅ Application created successfully")
|
91
|
-
|
92
83
|
def run(self, host: str = None, port: int = None, debug: bool = False):
|
93
|
-
"""Run the application."""
|
84
|
+
"""Run the application using the factory method."""
|
94
85
|
# Override configuration if specified
|
86
|
+
config_overrides = {}
|
95
87
|
if host:
|
96
|
-
|
88
|
+
config_overrides["host"] = host
|
97
89
|
if port:
|
98
|
-
|
90
|
+
config_overrides["port"] = port
|
99
91
|
if debug:
|
100
|
-
|
101
|
-
|
102
|
-
|
92
|
+
config_overrides["debug"] = True
|
93
|
+
print(f"🚀 Starting Full Application Example")
|
94
|
+
print(f"📋 Configuration: {self.config_path}")
|
95
|
+
print(f"🔧 Features: Built-in commands, Custom commands, Dynamic commands, Hooks, Proxy endpoints")
|
96
|
+
print("=" * 60)
|
97
|
+
# Create application with configuration
|
103
98
|
self.create_application()
|
104
|
-
|
105
99
|
# Get server configuration
|
106
100
|
server_host = self.config.get("server.host", "0.0.0.0")
|
107
101
|
server_port = self.config.get("server.port", 8000)
|
108
102
|
server_debug = self.config.get("server.debug", False)
|
109
|
-
|
110
|
-
|
111
|
-
|
103
|
+
# Get SSL configuration
|
104
|
+
ssl_enabled = self.config.get("ssl.enabled", False)
|
105
|
+
ssl_cert_file = self.config.get("ssl.cert_file")
|
106
|
+
ssl_key_file = self.config.get("ssl.key_file")
|
107
|
+
ssl_ca_cert = self.config.get("ssl.ca_cert")
|
108
|
+
verify_client = self.config.get("ssl.verify_client", False)
|
112
109
|
print(f"🌐 Server: {server_host}:{server_port}")
|
113
110
|
print(f"🔧 Debug: {server_debug}")
|
114
|
-
|
111
|
+
if ssl_enabled:
|
112
|
+
print(f"🔐 SSL: Enabled")
|
113
|
+
print(f" Certificate: {ssl_cert_file}")
|
114
|
+
print(f" Key: {ssl_key_file}")
|
115
|
+
if ssl_ca_cert:
|
116
|
+
print(f" CA: {ssl_ca_cert}")
|
117
|
+
print(f" Client verification: {verify_client}")
|
115
118
|
print("=" * 60)
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
119
|
+
# Use hypercorn directly to run the application with proxy endpoints
|
120
|
+
try:
|
121
|
+
import hypercorn.asyncio
|
122
|
+
import hypercorn.config
|
123
|
+
import asyncio
|
124
|
+
# Configure hypercorn
|
125
|
+
config_hypercorn = hypercorn.config.Config()
|
126
|
+
config_hypercorn.bind = [f"{server_host}:{server_port}"]
|
127
|
+
config_hypercorn.loglevel = "debug" if server_debug else "info"
|
128
|
+
if ssl_enabled and ssl_cert_file and ssl_key_file:
|
129
|
+
config_hypercorn.certfile = ssl_cert_file
|
130
|
+
config_hypercorn.keyfile = ssl_key_file
|
131
|
+
if ssl_ca_cert:
|
132
|
+
config_hypercorn.ca_certs = ssl_ca_cert
|
133
|
+
if verify_client:
|
134
|
+
import ssl
|
135
|
+
config_hypercorn.verify_mode = ssl.CERT_REQUIRED
|
136
|
+
print(f"🔐 Starting HTTPS server with hypercorn...")
|
137
|
+
else:
|
138
|
+
print(f"🌐 Starting HTTP server with hypercorn...")
|
139
|
+
# Run the server
|
140
|
+
asyncio.run(hypercorn.asyncio.serve(self.app, config_hypercorn))
|
141
|
+
except ImportError:
|
142
|
+
print("❌ hypercorn not installed. Installing...")
|
143
|
+
import subprocess
|
144
|
+
subprocess.run([sys.executable, "-m", "pip", "install", "hypercorn"])
|
145
|
+
print("✅ hypercorn installed. Please restart the application.")
|
146
|
+
return
|
122
147
|
def main():
|
123
148
|
"""Main entry point for the full application example."""
|
124
149
|
parser = argparse.ArgumentParser(description="Full Application Example")
|
@@ -126,13 +151,9 @@ def main():
|
|
126
151
|
parser.add_argument("--host", help="Server host")
|
127
152
|
parser.add_argument("--port", type=int, help="Server port")
|
128
153
|
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
129
|
-
|
130
154
|
args = parser.parse_args()
|
131
|
-
|
132
155
|
# Create and run application
|
133
156
|
app = FullApplication(args.config)
|
134
157
|
app.run(host=args.host, port=args.port, debug=args.debug)
|
135
|
-
|
136
|
-
|
137
158
|
if __name__ == "__main__":
|
138
159
|
main()
|