mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.1.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 +254 -33
- mcp_proxy_adapter/api/handlers.py +32 -6
- mcp_proxy_adapter/api/middleware/__init__.py +36 -30
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
- mcp_proxy_adapter/api/middleware/factory.py +243 -0
- mcp_proxy_adapter/api/middleware/logging.py +32 -6
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +152 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
- mcp_proxy_adapter/commands/__init__.py +19 -4
- mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
- mcp_proxy_adapter/commands/base.py +66 -32
- mcp_proxy_adapter/commands/builtin_commands.py +95 -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 +711 -354
- mcp_proxy_adapter/commands/dependency_manager.py +245 -0
- mcp_proxy_adapter/commands/echo_command.py +81 -0
- mcp_proxy_adapter/commands/health_command.py +7 -0
- mcp_proxy_adapter/commands/help_command.py +21 -14
- 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 +409 -0
- mcp_proxy_adapter/commands/reload_command.py +48 -50
- mcp_proxy_adapter/commands/result.py +1 -0
- mcp_proxy_adapter/commands/role_test_command.py +141 -0
- mcp_proxy_adapter/commands/roles_management_command.py +697 -0
- mcp_proxy_adapter/commands/security_command.py +488 -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 +159 -2
- mcp_proxy_adapter/core/app_factory.py +326 -0
- mcp_proxy_adapter/core/auth_validator.py +606 -0
- mcp_proxy_adapter/core/certificate_utils.py +827 -0
- mcp_proxy_adapter/core/client_security.py +384 -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 +19 -3
- mcp_proxy_adapter/core/mtls_asgi.py +156 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/protocol_manager.py +235 -0
- mcp_proxy_adapter/core/proxy_client.py +602 -0
- mcp_proxy_adapter/core/proxy_registration.py +522 -0
- mcp_proxy_adapter/core/role_utils.py +426 -0
- mcp_proxy_adapter/core/security_adapter.py +370 -0
- mcp_proxy_adapter/core/security_factory.py +239 -0
- mcp_proxy_adapter/core/security_integration.py +277 -0
- mcp_proxy_adapter/core/server_adapter.py +345 -0
- mcp_proxy_adapter/core/server_engine.py +364 -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/core/unified_config_adapter.py +579 -0
- mcp_proxy_adapter/custom_openapi.py +22 -11
- mcp_proxy_adapter/examples/README.md +230 -97
- mcp_proxy_adapter/examples/README_EN.md +258 -0
- mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
- mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
- mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
- mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
- mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +39 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +25 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
- mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
- mcp_proxy_adapter/examples/cert_config.json +9 -0
- mcp_proxy_adapter/examples/certs/admin.crt +32 -0
- mcp_proxy_adapter/examples/certs/admin.key +52 -0
- mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
- mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
- mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
- mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
- mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
- mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
- mcp_proxy_adapter/examples/certs/client.crt +32 -0
- mcp_proxy_adapter/examples/certs/client.key +52 -0
- mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
- mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
- mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
- mcp_proxy_adapter/examples/certs/client_user.key +52 -0
- mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
- mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
- mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
- mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
- mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
- mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
- mcp_proxy_adapter/examples/certs/readonly.key +52 -0
- mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
- mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
- mcp_proxy_adapter/examples/certs/server.crt +32 -0
- mcp_proxy_adapter/examples/certs/server.key +52 -0
- mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
- mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
- mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
- mcp_proxy_adapter/examples/certs/user.crt +32 -0
- mcp_proxy_adapter/examples/certs/user.key +52 -0
- mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
- mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
- mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
- mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
- mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
- mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
- mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
- mcp_proxy_adapter/examples/commands/__init__.py +1 -0
- mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
- mcp_proxy_adapter/examples/debug_request_state.py +144 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
- mcp_proxy_adapter/examples/demo_client.py +341 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
- mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
- mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
- mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
- mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
- mcp_proxy_adapter/examples/full_application/main.py +138 -0
- mcp_proxy_adapter/examples/full_application/roles.json +21 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
- mcp_proxy_adapter/examples/generate_certificates.py +121 -0
- mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
- mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
- mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
- mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
- mcp_proxy_adapter/examples/roles.json +38 -0
- mcp_proxy_adapter/examples/run_example.py +81 -0
- mcp_proxy_adapter/examples/run_security_tests.py +326 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
- mcp_proxy_adapter/examples/security_test_client.py +743 -0
- mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
- mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
- mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
- mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
- mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
- mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
- mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
- mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
- mcp_proxy_adapter/examples/test_examples.py +344 -0
- mcp_proxy_adapter/examples/universal_client.py +628 -0
- mcp_proxy_adapter/main.py +186 -0
- mcp_proxy_adapter/utils/config_generator.py +639 -0
- mcp_proxy_adapter/version.py +2 -1
- mcp_proxy_adapter-6.1.0.dist-info/METADATA +205 -0
- mcp_proxy_adapter-6.1.0.dist-info/RECORD +193 -0
- mcp_proxy_adapter-6.1.0.dist-info/entry_points.txt +2 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/licenses/LICENSE +2 -2
- mcp_proxy_adapter/api/middleware/auth.py +0 -146
- mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
- mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
- mcp_proxy_adapter/examples/__init__.py +0 -7
- mcp_proxy_adapter/examples/basic_server/README.md +0 -60
- mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
- mcp_proxy_adapter/examples/basic_server/config.json +0 -35
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
- mcp_proxy_adapter/examples/basic_server/server.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
- mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
- mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
- mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
- mcp_proxy_adapter/examples/deployment/README.md +0 -49
- mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
- mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
- mcp_proxy_adapter/examples/deployment/config.json +0 -29
- mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
- mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
- mcp_proxy_adapter/examples/deployment/run.sh +0 -43
- mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
- mcp_proxy_adapter/schemas/base_schema.json +0 -114
- mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +0 -3
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
- mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
- mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
- mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
- mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
- mcp_proxy_adapter/tests/commands/__init__.py +0 -3
- mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
- mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
- mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
- mcp_proxy_adapter/tests/conftest.py +0 -131
- mcp_proxy_adapter/tests/functional/__init__.py +0 -3
- mcp_proxy_adapter/tests/functional/test_api.py +0 -253
- mcp_proxy_adapter/tests/integration/__init__.py +0 -3
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
- mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
- mcp_proxy_adapter/tests/performance/__init__.py +0 -3
- mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
- mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
- mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
- mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
- mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
- mcp_proxy_adapter/tests/test_base_command.py +0 -123
- mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
- mcp_proxy_adapter/tests/test_command_registry.py +0 -281
- mcp_proxy_adapter/tests/test_config.py +0 -127
- mcp_proxy_adapter/tests/test_utils.py +0 -65
- mcp_proxy_adapter/tests/unit/__init__.py +0 -3
- mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
- mcp_proxy_adapter/tests/unit/test_config.py +0 -217
- mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
- mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,341 @@
|
|
1
|
+
"""
|
2
|
+
Demo Client Script
|
3
|
+
|
4
|
+
This script demonstrates how to use the UniversalClient with different
|
5
|
+
authentication methods and connection types.
|
6
|
+
|
7
|
+
Author: Vasiliy Zdanovskiy
|
8
|
+
email: vasilyvz@gmail.com
|
9
|
+
"""
|
10
|
+
|
11
|
+
import asyncio
|
12
|
+
import json
|
13
|
+
import sys
|
14
|
+
from pathlib import Path
|
15
|
+
|
16
|
+
# Add project root to path
|
17
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
18
|
+
|
19
|
+
from examples.universal_client import UniversalClient, create_client_config
|
20
|
+
|
21
|
+
|
22
|
+
async def demo_from_config_file(config_file: str):
|
23
|
+
"""
|
24
|
+
Demo client using configuration from file.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
config_file: Path to configuration file
|
28
|
+
"""
|
29
|
+
print(f"🚀 Demo from config file: {config_file}")
|
30
|
+
print("=" * 50)
|
31
|
+
|
32
|
+
try:
|
33
|
+
# Load configuration
|
34
|
+
with open(config_file, 'r') as f:
|
35
|
+
config = json.load(f)
|
36
|
+
|
37
|
+
print(f"Configuration loaded: {config.get('security', {}).get('auth_method', 'none')} auth")
|
38
|
+
|
39
|
+
# Create and use client
|
40
|
+
async with UniversalClient(config) as client:
|
41
|
+
# Test connection
|
42
|
+
success = await client.test_connection()
|
43
|
+
|
44
|
+
if success:
|
45
|
+
print("✅ Connection successful!")
|
46
|
+
|
47
|
+
# Test security features
|
48
|
+
security_results = await client.test_security_features()
|
49
|
+
print("\nSecurity Features:")
|
50
|
+
for feature, status in security_results.items():
|
51
|
+
status_icon = "✅" if status else "❌"
|
52
|
+
print(f" {status_icon} {feature}: {status}")
|
53
|
+
|
54
|
+
# Make API calls
|
55
|
+
await demo_api_calls(client)
|
56
|
+
else:
|
57
|
+
print("❌ Connection failed")
|
58
|
+
|
59
|
+
except FileNotFoundError:
|
60
|
+
print(f"❌ Configuration file not found: {config_file}")
|
61
|
+
except json.JSONDecodeError:
|
62
|
+
print(f"❌ Invalid JSON in configuration file: {config_file}")
|
63
|
+
except Exception as e:
|
64
|
+
print(f"❌ Demo failed: {e}")
|
65
|
+
|
66
|
+
|
67
|
+
async def demo_api_calls(client: UniversalClient):
|
68
|
+
"""Demonstrate various API calls."""
|
69
|
+
print("\n📡 API Calls Demo:")
|
70
|
+
print("-" * 30)
|
71
|
+
|
72
|
+
# Test health endpoint
|
73
|
+
try:
|
74
|
+
health = await client.get("/health")
|
75
|
+
print(f"Health: {health}")
|
76
|
+
except Exception as e:
|
77
|
+
print(f"Health check failed: {e}")
|
78
|
+
|
79
|
+
# Test status endpoint
|
80
|
+
try:
|
81
|
+
status = await client.get("/api/status")
|
82
|
+
print(f"Status: {status}")
|
83
|
+
except Exception as e:
|
84
|
+
print(f"Status check failed: {e}")
|
85
|
+
|
86
|
+
# Test JSON-RPC command
|
87
|
+
try:
|
88
|
+
command_data = {
|
89
|
+
"jsonrpc": "2.0",
|
90
|
+
"method": "test_command",
|
91
|
+
"params": {
|
92
|
+
"message": "Hello from universal client!",
|
93
|
+
"timestamp": "2024-01-01T00:00:00Z"
|
94
|
+
},
|
95
|
+
"id": 1
|
96
|
+
}
|
97
|
+
|
98
|
+
result = await client.post("/api/jsonrpc", command_data)
|
99
|
+
print(f"Command Result: {result}")
|
100
|
+
except Exception as e:
|
101
|
+
print(f"Command execution failed: {e}")
|
102
|
+
|
103
|
+
# Test security command if available
|
104
|
+
try:
|
105
|
+
security_data = {
|
106
|
+
"jsonrpc": "2.0",
|
107
|
+
"method": "security_command",
|
108
|
+
"params": {
|
109
|
+
"action": "get_status",
|
110
|
+
"include_certificates": True
|
111
|
+
},
|
112
|
+
"id": 2
|
113
|
+
}
|
114
|
+
|
115
|
+
result = await client.post("/api/jsonrpc", security_data)
|
116
|
+
print(f"Security Status: {result}")
|
117
|
+
except Exception as e:
|
118
|
+
print(f"Security command failed: {e}")
|
119
|
+
|
120
|
+
|
121
|
+
async def demo_all_configs():
|
122
|
+
"""Demo all available client configurations."""
|
123
|
+
print("🚀 Demo All Client Configurations")
|
124
|
+
print("=" * 50)
|
125
|
+
|
126
|
+
config_dir = Path(__file__).parent / "client_configs"
|
127
|
+
|
128
|
+
if not config_dir.exists():
|
129
|
+
print(f"❌ Config directory not found: {config_dir}")
|
130
|
+
return
|
131
|
+
|
132
|
+
config_files = list(config_dir.glob("*.json"))
|
133
|
+
|
134
|
+
if not config_files:
|
135
|
+
print(f"❌ No configuration files found in {config_dir}")
|
136
|
+
return
|
137
|
+
|
138
|
+
print(f"Found {len(config_files)} configuration files:")
|
139
|
+
for config_file in config_files:
|
140
|
+
print(f" - {config_file.name}")
|
141
|
+
|
142
|
+
print("\n" + "=" * 50)
|
143
|
+
|
144
|
+
for config_file in config_files:
|
145
|
+
await demo_from_config_file(str(config_file))
|
146
|
+
print("\n" + "-" * 50)
|
147
|
+
|
148
|
+
|
149
|
+
async def demo_programmatic_config():
|
150
|
+
"""Demo client with programmatically created configuration."""
|
151
|
+
print("🚀 Demo Programmatic Configuration")
|
152
|
+
print("=" * 50)
|
153
|
+
|
154
|
+
# Create different configurations programmatically
|
155
|
+
configs = [
|
156
|
+
{
|
157
|
+
"name": "API Key Client",
|
158
|
+
"config": create_client_config(
|
159
|
+
"http://localhost:8000",
|
160
|
+
"api_key",
|
161
|
+
api_key="demo_api_key_123"
|
162
|
+
)
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"name": "JWT Client",
|
166
|
+
"config": create_client_config(
|
167
|
+
"http://localhost:8000",
|
168
|
+
"jwt",
|
169
|
+
username="demo_user",
|
170
|
+
password="demo_password",
|
171
|
+
secret="demo_jwt_secret"
|
172
|
+
)
|
173
|
+
},
|
174
|
+
{
|
175
|
+
"name": "Certificate Client",
|
176
|
+
"config": create_client_config(
|
177
|
+
"https://localhost:8443",
|
178
|
+
"certificate",
|
179
|
+
cert_file="./certs/client.crt",
|
180
|
+
key_file="./keys/client.key",
|
181
|
+
ca_cert_file="./certs/ca.crt"
|
182
|
+
)
|
183
|
+
},
|
184
|
+
{
|
185
|
+
"name": "Basic Auth Client",
|
186
|
+
"config": create_client_config(
|
187
|
+
"http://localhost:8000",
|
188
|
+
"basic",
|
189
|
+
username="demo_user",
|
190
|
+
password="demo_password"
|
191
|
+
)
|
192
|
+
}
|
193
|
+
]
|
194
|
+
|
195
|
+
for config_info in configs:
|
196
|
+
print(f"\n📋 Testing: {config_info['name']}")
|
197
|
+
print("-" * 30)
|
198
|
+
|
199
|
+
try:
|
200
|
+
async with UniversalClient(config_info["config"]) as client:
|
201
|
+
success = await client.test_connection()
|
202
|
+
|
203
|
+
if success:
|
204
|
+
print("✅ Connection successful!")
|
205
|
+
await demo_api_calls(client)
|
206
|
+
else:
|
207
|
+
print("❌ Connection failed")
|
208
|
+
|
209
|
+
except Exception as e:
|
210
|
+
print(f"❌ Test failed: {e}")
|
211
|
+
|
212
|
+
|
213
|
+
async def interactive_demo():
|
214
|
+
"""Interactive demo with user input."""
|
215
|
+
print("🚀 Interactive Client Demo")
|
216
|
+
print("=" * 50)
|
217
|
+
|
218
|
+
print("Available authentication methods:")
|
219
|
+
print("1. No authentication")
|
220
|
+
print("2. API Key")
|
221
|
+
print("3. JWT Token")
|
222
|
+
print("4. Certificate")
|
223
|
+
print("5. Basic Authentication")
|
224
|
+
|
225
|
+
try:
|
226
|
+
choice = input("\nSelect authentication method (1-5): ").strip()
|
227
|
+
|
228
|
+
auth_methods = {
|
229
|
+
"1": "none",
|
230
|
+
"2": "api_key",
|
231
|
+
"3": "jwt",
|
232
|
+
"4": "certificate",
|
233
|
+
"5": "basic"
|
234
|
+
}
|
235
|
+
|
236
|
+
if choice not in auth_methods:
|
237
|
+
print("❌ Invalid choice")
|
238
|
+
return
|
239
|
+
|
240
|
+
auth_method = auth_methods[choice]
|
241
|
+
|
242
|
+
# Get server URL
|
243
|
+
server_url = input("Enter server URL (default: http://localhost:8000): ").strip()
|
244
|
+
if not server_url:
|
245
|
+
server_url = "http://localhost:8000"
|
246
|
+
|
247
|
+
# Create configuration based on choice
|
248
|
+
config_kwargs = {}
|
249
|
+
|
250
|
+
if auth_method == "api_key":
|
251
|
+
api_key = input("Enter API key: ").strip()
|
252
|
+
if api_key:
|
253
|
+
config_kwargs["api_key"] = api_key
|
254
|
+
|
255
|
+
elif auth_method == "jwt":
|
256
|
+
username = input("Enter username: ").strip()
|
257
|
+
password = input("Enter password: ").strip()
|
258
|
+
secret = input("Enter JWT secret: ").strip()
|
259
|
+
if username and password and secret:
|
260
|
+
config_kwargs.update({
|
261
|
+
"username": username,
|
262
|
+
"password": password,
|
263
|
+
"secret": secret
|
264
|
+
})
|
265
|
+
|
266
|
+
elif auth_method == "certificate":
|
267
|
+
cert_file = input("Enter certificate file path: ").strip()
|
268
|
+
key_file = input("Enter key file path: ").strip()
|
269
|
+
ca_cert_file = input("Enter CA certificate file path: ").strip()
|
270
|
+
if cert_file and key_file:
|
271
|
+
config_kwargs.update({
|
272
|
+
"cert_file": cert_file,
|
273
|
+
"key_file": key_file,
|
274
|
+
"ca_cert_file": ca_cert_file
|
275
|
+
})
|
276
|
+
|
277
|
+
elif auth_method == "basic":
|
278
|
+
username = input("Enter username: ").strip()
|
279
|
+
password = input("Enter password: ").strip()
|
280
|
+
if username and password:
|
281
|
+
config_kwargs.update({
|
282
|
+
"username": username,
|
283
|
+
"password": password
|
284
|
+
})
|
285
|
+
|
286
|
+
# Create configuration
|
287
|
+
config = create_client_config(server_url, auth_method, **config_kwargs)
|
288
|
+
|
289
|
+
print(f"\nConfiguration created for {auth_method} authentication")
|
290
|
+
print(f"Server URL: {server_url}")
|
291
|
+
|
292
|
+
# Test connection
|
293
|
+
async with UniversalClient(config) as client:
|
294
|
+
success = await client.test_connection()
|
295
|
+
|
296
|
+
if success:
|
297
|
+
print("✅ Connection successful!")
|
298
|
+
await demo_api_calls(client)
|
299
|
+
else:
|
300
|
+
print("❌ Connection failed")
|
301
|
+
|
302
|
+
except KeyboardInterrupt:
|
303
|
+
print("\n\nDemo interrupted by user")
|
304
|
+
except Exception as e:
|
305
|
+
print(f"❌ Interactive demo failed: {e}")
|
306
|
+
|
307
|
+
|
308
|
+
def main():
|
309
|
+
"""Main demo function."""
|
310
|
+
if len(sys.argv) > 1:
|
311
|
+
command = sys.argv[1]
|
312
|
+
|
313
|
+
if command == "config":
|
314
|
+
if len(sys.argv) > 2:
|
315
|
+
config_file = sys.argv[2]
|
316
|
+
asyncio.run(demo_from_config_file(config_file))
|
317
|
+
else:
|
318
|
+
print("Usage: python demo_client.py config <config_file>")
|
319
|
+
|
320
|
+
elif command == "all":
|
321
|
+
asyncio.run(demo_all_configs())
|
322
|
+
|
323
|
+
elif command == "programmatic":
|
324
|
+
asyncio.run(demo_programmatic_config())
|
325
|
+
|
326
|
+
elif command == "interactive":
|
327
|
+
asyncio.run(interactive_demo())
|
328
|
+
|
329
|
+
else:
|
330
|
+
print("Unknown command. Available commands:")
|
331
|
+
print(" config <file> - Demo with config file")
|
332
|
+
print(" all - Demo all config files")
|
333
|
+
print(" programmatic - Demo programmatic configs")
|
334
|
+
print(" interactive - Interactive demo")
|
335
|
+
else:
|
336
|
+
# Default: demo all configs
|
337
|
+
asyncio.run(demo_all_configs())
|
338
|
+
|
339
|
+
|
340
|
+
if __name__ == "__main__":
|
341
|
+
main()
|
@@ -0,0 +1,99 @@
|
|
1
|
+
"""
|
2
|
+
Custom Echo Command
|
3
|
+
|
4
|
+
This module demonstrates a custom command implementation for the full application example.
|
5
|
+
|
6
|
+
Author: Vasiliy Zdanovskiy
|
7
|
+
email: vasilyvz@gmail.com
|
8
|
+
"""
|
9
|
+
|
10
|
+
from typing import Dict, Any, Optional
|
11
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
12
|
+
from mcp_proxy_adapter.commands.result import CommandResult
|
13
|
+
|
14
|
+
|
15
|
+
class CustomEchoResult(CommandResult):
|
16
|
+
"""Result class for custom echo command."""
|
17
|
+
|
18
|
+
def __init__(self, message: str, timestamp: str, echo_count: int):
|
19
|
+
self.message = message
|
20
|
+
self.timestamp = timestamp
|
21
|
+
self.echo_count = echo_count
|
22
|
+
|
23
|
+
def to_dict(self) -> Dict[str, Any]:
|
24
|
+
"""Convert result to dictionary."""
|
25
|
+
return {
|
26
|
+
"message": self.message,
|
27
|
+
"timestamp": self.timestamp,
|
28
|
+
"echo_count": self.echo_count,
|
29
|
+
"command_type": "custom_echo"
|
30
|
+
}
|
31
|
+
|
32
|
+
def get_schema(self) -> Dict[str, Any]:
|
33
|
+
"""Get result schema."""
|
34
|
+
return {
|
35
|
+
"type": "object",
|
36
|
+
"properties": {
|
37
|
+
"message": {"type": "string", "description": "Echoed message"},
|
38
|
+
"timestamp": {"type": "string", "description": "Timestamp of echo"},
|
39
|
+
"echo_count": {"type": "integer", "description": "Number of echoes"},
|
40
|
+
"command_type": {"type": "string", "description": "Command type"}
|
41
|
+
},
|
42
|
+
"required": ["message", "timestamp", "echo_count", "command_type"]
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
class CustomEchoCommand(BaseCommand):
|
47
|
+
"""Custom echo command implementation."""
|
48
|
+
|
49
|
+
def __init__(self):
|
50
|
+
super().__init__()
|
51
|
+
self.echo_count = 0
|
52
|
+
|
53
|
+
def get_name(self) -> str:
|
54
|
+
"""Get command name."""
|
55
|
+
return "custom_echo"
|
56
|
+
|
57
|
+
def get_description(self) -> str:
|
58
|
+
"""Get command description."""
|
59
|
+
return "Custom echo command with enhanced features"
|
60
|
+
|
61
|
+
def get_schema(self) -> Dict[str, Any]:
|
62
|
+
"""Get command schema."""
|
63
|
+
return {
|
64
|
+
"type": "object",
|
65
|
+
"properties": {
|
66
|
+
"message": {
|
67
|
+
"type": "string",
|
68
|
+
"description": "Message to echo",
|
69
|
+
"default": "Hello from custom echo!"
|
70
|
+
},
|
71
|
+
"repeat": {
|
72
|
+
"type": "integer",
|
73
|
+
"description": "Number of times to repeat",
|
74
|
+
"default": 1,
|
75
|
+
"minimum": 1,
|
76
|
+
"maximum": 10
|
77
|
+
}
|
78
|
+
},
|
79
|
+
"required": ["message"]
|
80
|
+
}
|
81
|
+
|
82
|
+
async def execute(self, params: Dict[str, Any]) -> CustomEchoResult:
|
83
|
+
"""Execute the custom echo command."""
|
84
|
+
message = params.get("message", "Hello from custom echo!")
|
85
|
+
repeat = min(max(params.get("repeat", 1), 1), 10)
|
86
|
+
|
87
|
+
self.echo_count += 1
|
88
|
+
|
89
|
+
from datetime import datetime
|
90
|
+
timestamp = datetime.now().isoformat()
|
91
|
+
|
92
|
+
# Repeat the message
|
93
|
+
echoed_message = " ".join([message] * repeat)
|
94
|
+
|
95
|
+
return CustomEchoResult(
|
96
|
+
message=echoed_message,
|
97
|
+
timestamp=timestamp,
|
98
|
+
echo_count=self.echo_count
|
99
|
+
)
|
@@ -0,0 +1,106 @@
|
|
1
|
+
"""
|
2
|
+
Dynamic Calculator Command
|
3
|
+
|
4
|
+
This module demonstrates a dynamically loaded command implementation for the full application example.
|
5
|
+
|
6
|
+
Author: Vasiliy Zdanovskiy
|
7
|
+
email: vasilyvz@gmail.com
|
8
|
+
"""
|
9
|
+
|
10
|
+
from typing import Dict, Any, Optional
|
11
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
12
|
+
from mcp_proxy_adapter.commands.result import CommandResult
|
13
|
+
|
14
|
+
|
15
|
+
class CalculatorResult(CommandResult):
|
16
|
+
"""Result class for calculator command."""
|
17
|
+
|
18
|
+
def __init__(self, operation: str, result: float, expression: str):
|
19
|
+
self.operation = operation
|
20
|
+
self.result = result
|
21
|
+
self.expression = expression
|
22
|
+
|
23
|
+
def to_dict(self) -> Dict[str, Any]:
|
24
|
+
"""Convert result to dictionary."""
|
25
|
+
return {
|
26
|
+
"operation": self.operation,
|
27
|
+
"result": self.result,
|
28
|
+
"expression": self.expression,
|
29
|
+
"command_type": "dynamic_calculator"
|
30
|
+
}
|
31
|
+
|
32
|
+
def get_schema(self) -> Dict[str, Any]:
|
33
|
+
"""Get result schema."""
|
34
|
+
return {
|
35
|
+
"type": "object",
|
36
|
+
"properties": {
|
37
|
+
"operation": {"type": "string", "description": "Mathematical operation"},
|
38
|
+
"result": {"type": "number", "description": "Calculation result"},
|
39
|
+
"expression": {"type": "string", "description": "Full expression"},
|
40
|
+
"command_type": {"type": "string", "description": "Command type"}
|
41
|
+
},
|
42
|
+
"required": ["operation", "result", "expression", "command_type"]
|
43
|
+
}
|
44
|
+
|
45
|
+
|
46
|
+
class DynamicCalculatorCommand(BaseCommand):
|
47
|
+
"""Dynamic calculator command implementation."""
|
48
|
+
|
49
|
+
def get_name(self) -> str:
|
50
|
+
"""Get command name."""
|
51
|
+
return "dynamic_calculator"
|
52
|
+
|
53
|
+
def get_description(self) -> str:
|
54
|
+
"""Get command description."""
|
55
|
+
return "Dynamic calculator with basic mathematical operations"
|
56
|
+
|
57
|
+
def get_schema(self) -> Dict[str, Any]:
|
58
|
+
"""Get command schema."""
|
59
|
+
return {
|
60
|
+
"type": "object",
|
61
|
+
"properties": {
|
62
|
+
"operation": {
|
63
|
+
"type": "string",
|
64
|
+
"description": "Mathematical operation (add, subtract, multiply, divide)",
|
65
|
+
"enum": ["add", "subtract", "multiply", "divide"]
|
66
|
+
},
|
67
|
+
"a": {
|
68
|
+
"type": "number",
|
69
|
+
"description": "First number"
|
70
|
+
},
|
71
|
+
"b": {
|
72
|
+
"type": "number",
|
73
|
+
"description": "Second number"
|
74
|
+
}
|
75
|
+
},
|
76
|
+
"required": ["operation", "a", "b"]
|
77
|
+
}
|
78
|
+
|
79
|
+
async def execute(self, params: Dict[str, Any]) -> CalculatorResult:
|
80
|
+
"""Execute the calculator command."""
|
81
|
+
operation = params.get("operation")
|
82
|
+
a = params.get("a")
|
83
|
+
b = params.get("b")
|
84
|
+
|
85
|
+
if operation == "add":
|
86
|
+
result = a + b
|
87
|
+
expression = f"{a} + {b}"
|
88
|
+
elif operation == "subtract":
|
89
|
+
result = a - b
|
90
|
+
expression = f"{a} - {b}"
|
91
|
+
elif operation == "multiply":
|
92
|
+
result = a * b
|
93
|
+
expression = f"{a} * {b}"
|
94
|
+
elif operation == "divide":
|
95
|
+
if b == 0:
|
96
|
+
raise ValueError("Division by zero is not allowed")
|
97
|
+
result = a / b
|
98
|
+
expression = f"{a} / {b}"
|
99
|
+
else:
|
100
|
+
raise ValueError(f"Unknown operation: {operation}")
|
101
|
+
|
102
|
+
return CalculatorResult(
|
103
|
+
operation=operation,
|
104
|
+
result=result,
|
105
|
+
expression=expression
|
106
|
+
)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
{
|
2
|
+
"server": {
|
3
|
+
"host": "0.0.0.0",
|
4
|
+
"port": 8001,
|
5
|
+
"debug": false,
|
6
|
+
"log_level": "INFO"
|
7
|
+
},
|
8
|
+
"ssl": {
|
9
|
+
"enabled": false
|
10
|
+
},
|
11
|
+
"security": {
|
12
|
+
"enabled": true,
|
13
|
+
"auth": {
|
14
|
+
"enabled": true,
|
15
|
+
"methods": ["api_key"],
|
16
|
+
"api_keys": {
|
17
|
+
"admin": "admin-secret-key-123",
|
18
|
+
"user": "user-secret-key-456"
|
19
|
+
}
|
20
|
+
},
|
21
|
+
"rate_limit": {
|
22
|
+
"enabled": true,
|
23
|
+
"requests_per_minute": 60,
|
24
|
+
"requests_per_hour": 1000,
|
25
|
+
"burst_limit": 10
|
26
|
+
}
|
27
|
+
},
|
28
|
+
"logging": {
|
29
|
+
"level": "INFO",
|
30
|
+
"console_output": true,
|
31
|
+
"file_output": false
|
32
|
+
},
|
33
|
+
"commands": {
|
34
|
+
"auto_discovery": true,
|
35
|
+
"commands_directory": "./commands"
|
36
|
+
}
|
37
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"server": {
|
3
|
+
"host": "0.0.0.0",
|
4
|
+
"port": 8000,
|
5
|
+
"debug": false,
|
6
|
+
"log_level": "INFO"
|
7
|
+
},
|
8
|
+
"ssl": {
|
9
|
+
"enabled": false
|
10
|
+
},
|
11
|
+
"security": {
|
12
|
+
"enabled": false
|
13
|
+
},
|
14
|
+
"logging": {
|
15
|
+
"level": "INFO",
|
16
|
+
"console_output": true,
|
17
|
+
"file_output": false
|
18
|
+
},
|
19
|
+
"commands": {
|
20
|
+
"auto_discovery": true,
|
21
|
+
"commands_directory": "./commands"
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
{
|
2
|
+
"server": {
|
3
|
+
"host": "0.0.0.0",
|
4
|
+
"port": 8444,
|
5
|
+
"debug": false,
|
6
|
+
"log_level": "INFO"
|
7
|
+
},
|
8
|
+
"ssl": {
|
9
|
+
"enabled": true,
|
10
|
+
"cert_file": "./certs/server.crt",
|
11
|
+
"key_file": "./certs/server.key"
|
12
|
+
},
|
13
|
+
"security": {
|
14
|
+
"enabled": true,
|
15
|
+
"auth": {
|
16
|
+
"enabled": true,
|
17
|
+
"methods": ["api_key"],
|
18
|
+
"api_keys": {
|
19
|
+
"admin": "admin-secret-key-123",
|
20
|
+
"user": "user-secret-key-456"
|
21
|
+
}
|
22
|
+
},
|
23
|
+
"rate_limit": {
|
24
|
+
"enabled": true,
|
25
|
+
"requests_per_minute": 60,
|
26
|
+
"requests_per_hour": 1000,
|
27
|
+
"burst_limit": 10
|
28
|
+
}
|
29
|
+
},
|
30
|
+
"logging": {
|
31
|
+
"level": "INFO",
|
32
|
+
"console_output": true,
|
33
|
+
"file_output": false
|
34
|
+
},
|
35
|
+
"commands": {
|
36
|
+
"auto_discovery": true,
|
37
|
+
"commands_directory": "./commands"
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
{
|
2
|
+
"server": {
|
3
|
+
"host": "0.0.0.0",
|
4
|
+
"port": 8443,
|
5
|
+
"debug": false,
|
6
|
+
"log_level": "INFO"
|
7
|
+
},
|
8
|
+
"ssl": {
|
9
|
+
"enabled": true,
|
10
|
+
"cert_file": "./certs/server.crt",
|
11
|
+
"key_file": "./certs/server.key"
|
12
|
+
},
|
13
|
+
"security": {
|
14
|
+
"enabled": false
|
15
|
+
},
|
16
|
+
"logging": {
|
17
|
+
"level": "INFO",
|
18
|
+
"console_output": true,
|
19
|
+
"file_output": false
|
20
|
+
},
|
21
|
+
"commands": {
|
22
|
+
"auto_discovery": true,
|
23
|
+
"commands_directory": "./commands"
|
24
|
+
}
|
25
|
+
}
|