mcp-proxy-adapter 6.0.0__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/api/app.py +174 -80
- mcp_proxy_adapter/api/handlers.py +16 -5
- mcp_proxy_adapter/api/middleware/__init__.py +7 -2
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
- mcp_proxy_adapter/api/middleware/factory.py +36 -12
- 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 +7 -1
- mcp_proxy_adapter/commands/base.py +7 -4
- mcp_proxy_adapter/commands/builtin_commands.py +8 -2
- mcp_proxy_adapter/commands/command_registry.py +8 -0
- mcp_proxy_adapter/commands/echo_command.py +81 -0
- mcp_proxy_adapter/commands/help_command.py +21 -14
- mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
- mcp_proxy_adapter/commands/role_test_command.py +141 -0
- mcp_proxy_adapter/commands/security_command.py +488 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
- mcp_proxy_adapter/commands/token_management_command.py +1 -1
- mcp_proxy_adapter/config.py +81 -21
- mcp_proxy_adapter/core/app_factory.py +326 -0
- mcp_proxy_adapter/core/client_security.py +384 -0
- mcp_proxy_adapter/core/logging.py +8 -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 +9 -0
- mcp_proxy_adapter/core/proxy_client.py +602 -0
- mcp_proxy_adapter/core/proxy_registration.py +299 -47
- mcp_proxy_adapter/core/security_adapter.py +12 -15
- 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/unified_config_adapter.py +579 -0
- 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 +21 -10
- 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-6.0.0.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/auth_adapter.py +0 -235
- mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
- mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
- mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
- mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
- mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
- mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
- mcp_proxy_adapter/api/middleware/security.py +0 -376
- mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
- 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 -70
- mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
- mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
- mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
- mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
- mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
- mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
- mcp_proxy_adapter/examples/basic_server/server.py +0 -114
- 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 -566
- 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/auto_commands/test_command.py +0 -105
- mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
- mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
- mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
- mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
- mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
- 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/full_help_response.json +0 -1
- mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
- mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
- 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/loadable_commands/test_ignored.py +0 -129
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
- mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
- mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
- mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
- mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
- mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
- mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
- mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
- mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
- 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/examples/simple_custom_commands/README.md +0 -149
- mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
- mcp_proxy_adapter/schemas/base_schema.json +0 -114
- mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
- mcp_proxy_adapter/schemas/roles_schema.json +0 -162
- 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 -270
- mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
- mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/top_level.txt +0 -0
@@ -1,281 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tests for command registry.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import pytest
|
6
|
-
from unittest.mock import MagicMock, patch
|
7
|
-
|
8
|
-
from mcp_proxy_adapter.commands.base import Command
|
9
|
-
from mcp_proxy_adapter.commands.result import CommandResult
|
10
|
-
from mcp_proxy_adapter.commands.command_registry import CommandRegistry
|
11
|
-
from mcp_proxy_adapter.core.errors import NotFoundError
|
12
|
-
|
13
|
-
|
14
|
-
class MockResult(CommandResult):
|
15
|
-
"""Test result class for testing."""
|
16
|
-
|
17
|
-
def __init__(self):
|
18
|
-
pass
|
19
|
-
|
20
|
-
def to_dict(self):
|
21
|
-
return {}
|
22
|
-
|
23
|
-
@classmethod
|
24
|
-
def get_schema(cls):
|
25
|
-
return {}
|
26
|
-
|
27
|
-
|
28
|
-
class TestCommand1(Command):
|
29
|
-
"""First test command."""
|
30
|
-
|
31
|
-
name = "test_command1"
|
32
|
-
result_class = MockResult
|
33
|
-
|
34
|
-
async def execute(self, **kwargs):
|
35
|
-
return MockResult()
|
36
|
-
|
37
|
-
|
38
|
-
class TestCommand2(Command):
|
39
|
-
"""Second test command."""
|
40
|
-
|
41
|
-
name = "test_command2"
|
42
|
-
result_class = MockResult
|
43
|
-
|
44
|
-
async def execute(self, **kwargs):
|
45
|
-
return MockResult()
|
46
|
-
|
47
|
-
|
48
|
-
def test_registry_initialization():
|
49
|
-
"""Test registry initialization."""
|
50
|
-
registry = CommandRegistry()
|
51
|
-
assert len(registry._commands) == 0
|
52
|
-
|
53
|
-
|
54
|
-
def test_register_command():
|
55
|
-
"""Test registering command."""
|
56
|
-
registry = CommandRegistry()
|
57
|
-
|
58
|
-
# Register first command
|
59
|
-
registry.register(TestCommand1)
|
60
|
-
assert len(registry._commands) == 1
|
61
|
-
assert "test_command1" in registry._commands
|
62
|
-
|
63
|
-
# Register second command
|
64
|
-
registry.register(TestCommand2)
|
65
|
-
assert len(registry._commands) == 2
|
66
|
-
assert "test_command2" in registry._commands
|
67
|
-
|
68
|
-
|
69
|
-
def test_register_duplicated_command():
|
70
|
-
"""Test registering duplicated command."""
|
71
|
-
registry = CommandRegistry()
|
72
|
-
|
73
|
-
# Register command
|
74
|
-
registry.register(TestCommand1)
|
75
|
-
|
76
|
-
# Try to register again
|
77
|
-
with pytest.raises(ValueError):
|
78
|
-
registry.register(TestCommand1)
|
79
|
-
|
80
|
-
|
81
|
-
def test_register_command_without_name():
|
82
|
-
"""Test registering command without name attribute."""
|
83
|
-
registry = CommandRegistry()
|
84
|
-
|
85
|
-
# Create command without name
|
86
|
-
class CommandWithoutName(Command):
|
87
|
-
result_class = MockResult
|
88
|
-
|
89
|
-
async def execute(self, **kwargs):
|
90
|
-
return MockResult()
|
91
|
-
|
92
|
-
# Register command
|
93
|
-
registry.register(CommandWithoutName)
|
94
|
-
|
95
|
-
# Check if registered with class name
|
96
|
-
assert "commandwithoutname" in registry._commands
|
97
|
-
|
98
|
-
|
99
|
-
def test_unregister_command():
|
100
|
-
"""Test unregistering command."""
|
101
|
-
registry = CommandRegistry()
|
102
|
-
|
103
|
-
# Register command
|
104
|
-
registry.register(TestCommand1)
|
105
|
-
assert "test_command1" in registry._commands
|
106
|
-
|
107
|
-
# Unregister command
|
108
|
-
registry.unregister("test_command1")
|
109
|
-
assert "test_command1" not in registry._commands
|
110
|
-
|
111
|
-
|
112
|
-
def test_unregister_nonexistent_command():
|
113
|
-
"""Test unregistering nonexistent command."""
|
114
|
-
registry = CommandRegistry()
|
115
|
-
|
116
|
-
# Try to unregister nonexistent command
|
117
|
-
with pytest.raises(NotFoundError):
|
118
|
-
registry.unregister("nonexistent")
|
119
|
-
|
120
|
-
|
121
|
-
def test_get_command():
|
122
|
-
"""Test getting command."""
|
123
|
-
registry = CommandRegistry()
|
124
|
-
|
125
|
-
# Register command
|
126
|
-
registry.register(TestCommand1)
|
127
|
-
|
128
|
-
# Get command
|
129
|
-
command = registry.get_command("test_command1")
|
130
|
-
assert command == TestCommand1
|
131
|
-
|
132
|
-
|
133
|
-
def test_get_nonexistent_command():
|
134
|
-
"""Test getting nonexistent command."""
|
135
|
-
registry = CommandRegistry()
|
136
|
-
|
137
|
-
# Try to get nonexistent command
|
138
|
-
with pytest.raises(NotFoundError):
|
139
|
-
registry.get_command("nonexistent")
|
140
|
-
|
141
|
-
|
142
|
-
def test_get_all_commands():
|
143
|
-
"""Test getting all commands."""
|
144
|
-
registry = CommandRegistry()
|
145
|
-
|
146
|
-
# Register commands
|
147
|
-
registry.register(TestCommand1)
|
148
|
-
registry.register(TestCommand2)
|
149
|
-
|
150
|
-
# Get all commands
|
151
|
-
commands = registry.get_all_commands()
|
152
|
-
assert len(commands) == 2
|
153
|
-
assert "test_command1" in commands
|
154
|
-
assert "test_command2" in commands
|
155
|
-
assert commands["test_command1"] == TestCommand1
|
156
|
-
assert commands["test_command2"] == TestCommand2
|
157
|
-
|
158
|
-
|
159
|
-
def test_get_command_info():
|
160
|
-
"""Test getting command info."""
|
161
|
-
registry = CommandRegistry()
|
162
|
-
|
163
|
-
# Register command
|
164
|
-
registry.register(TestCommand1)
|
165
|
-
|
166
|
-
# Get command info
|
167
|
-
info = registry.get_command_info("test_command1")
|
168
|
-
|
169
|
-
# Check info structure
|
170
|
-
assert info["name"] == "test_command1"
|
171
|
-
assert "description" in info
|
172
|
-
assert "params" in info
|
173
|
-
assert "schema" in info
|
174
|
-
assert "result_schema" in info
|
175
|
-
|
176
|
-
|
177
|
-
def test_get_all_commands_info():
|
178
|
-
"""Test getting all commands info."""
|
179
|
-
registry = CommandRegistry()
|
180
|
-
|
181
|
-
# Register commands
|
182
|
-
registry.register(TestCommand1)
|
183
|
-
registry.register(TestCommand2)
|
184
|
-
|
185
|
-
# Get all commands info
|
186
|
-
info = registry.get_all_commands_info()
|
187
|
-
|
188
|
-
# Check info structure
|
189
|
-
assert len(info) == 2
|
190
|
-
assert "test_command1" in info
|
191
|
-
assert "test_command2" in info
|
192
|
-
assert info["test_command1"]["name"] == "test_command1"
|
193
|
-
assert info["test_command2"]["name"] == "test_command2"
|
194
|
-
|
195
|
-
|
196
|
-
@patch("importlib.import_module")
|
197
|
-
@patch("pkgutil.iter_modules")
|
198
|
-
@patch("inspect.getmembers")
|
199
|
-
def test_discover_commands(mock_getmembers, mock_iter_modules, mock_import_module):
|
200
|
-
"""Test discovering commands."""
|
201
|
-
registry = CommandRegistry()
|
202
|
-
|
203
|
-
# Mock package
|
204
|
-
mock_package = MagicMock()
|
205
|
-
mock_package.__file__ = "/path/to/package"
|
206
|
-
mock_import_module.return_value = mock_package
|
207
|
-
|
208
|
-
# Mock modules
|
209
|
-
mock_iter_modules.return_value = [
|
210
|
-
(None, "test_command", False),
|
211
|
-
(None, "other_module", False)
|
212
|
-
]
|
213
|
-
|
214
|
-
# Mock command classes
|
215
|
-
class DiscoveredCommand(Command):
|
216
|
-
name = "discovered"
|
217
|
-
result_class = MockResult
|
218
|
-
|
219
|
-
async def execute(self, **kwargs):
|
220
|
-
return MockResult()
|
221
|
-
|
222
|
-
# Mock getmembers to return command class
|
223
|
-
mock_getmembers.return_value = [
|
224
|
-
("DiscoveredCommand", DiscoveredCommand)
|
225
|
-
]
|
226
|
-
|
227
|
-
# Discover commands
|
228
|
-
registry.discover_commands()
|
229
|
-
|
230
|
-
# Check if command was registered
|
231
|
-
assert len(mock_import_module.mock_calls) > 0
|
232
|
-
|
233
|
-
|
234
|
-
def test_clear_registry():
|
235
|
-
"""Test clearing registry."""
|
236
|
-
registry = CommandRegistry()
|
237
|
-
|
238
|
-
# Register commands
|
239
|
-
registry.register(TestCommand1)
|
240
|
-
registry.register(TestCommand2)
|
241
|
-
assert len(registry._commands) == 2
|
242
|
-
|
243
|
-
# Clear registry
|
244
|
-
registry.clear()
|
245
|
-
assert len(registry._commands) == 0
|
246
|
-
|
247
|
-
|
248
|
-
def test_register_command_instance():
|
249
|
-
"""Test registering a command instance (with dependencies)."""
|
250
|
-
registry = CommandRegistry()
|
251
|
-
|
252
|
-
class Service:
|
253
|
-
def __init__(self, value):
|
254
|
-
self.value = value
|
255
|
-
|
256
|
-
class CommandWithDependency(Command):
|
257
|
-
name = "command_with_dep"
|
258
|
-
result_class = MockResult
|
259
|
-
def __init__(self, service: Service):
|
260
|
-
self.service = service
|
261
|
-
async def execute(self, **kwargs):
|
262
|
-
# Return the value from the injected service
|
263
|
-
result = MockResult()
|
264
|
-
result.service_value = self.service.value
|
265
|
-
return result
|
266
|
-
|
267
|
-
service = Service(value=42)
|
268
|
-
command_instance = CommandWithDependency(service=service)
|
269
|
-
registry.register(command_instance)
|
270
|
-
|
271
|
-
# Проверяем, что экземпляр зарегистрирован
|
272
|
-
assert registry.has_instance("command_with_dep")
|
273
|
-
# Проверяем, что get_command_instance возвращает именно этот экземпляр
|
274
|
-
assert registry.get_command_instance("command_with_dep") is command_instance
|
275
|
-
# Проверяем, что execute использует внедрённый сервис
|
276
|
-
import asyncio
|
277
|
-
result = asyncio.run(
|
278
|
-
registry.get_command_instance("command_with_dep").execute()
|
279
|
-
)
|
280
|
-
assert hasattr(result, "service_value")
|
281
|
-
assert result.service_value == 42
|
@@ -1,127 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Test module for configuration class.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import os
|
6
|
-
import json
|
7
|
-
import tempfile
|
8
|
-
from pathlib import Path
|
9
|
-
|
10
|
-
import pytest
|
11
|
-
|
12
|
-
from mcp_proxy_adapter.config import Config
|
13
|
-
|
14
|
-
|
15
|
-
def test_config_initialization(temp_config_file):
|
16
|
-
"""
|
17
|
-
Test configuration initialization.
|
18
|
-
"""
|
19
|
-
config = Config(temp_config_file)
|
20
|
-
assert config.config_path == temp_config_file
|
21
|
-
assert isinstance(config.config_data, dict)
|
22
|
-
|
23
|
-
|
24
|
-
def test_config_get_existing_values(test_config):
|
25
|
-
"""
|
26
|
-
Test getting existing values from configuration.
|
27
|
-
"""
|
28
|
-
# Test top-level key
|
29
|
-
server_config = test_config.get("server")
|
30
|
-
assert server_config.get("host") == "127.0.0.1"
|
31
|
-
assert server_config.get("port") == 8888
|
32
|
-
|
33
|
-
# Test nested key with dot notation
|
34
|
-
assert test_config.get("server.host") == "127.0.0.1"
|
35
|
-
assert test_config.get("server.port") == 8888
|
36
|
-
|
37
|
-
# Test logging values
|
38
|
-
assert test_config.get("logging.level") == "DEBUG"
|
39
|
-
assert test_config.get("logging.file") is None
|
40
|
-
|
41
|
-
|
42
|
-
def test_config_get_default_values(test_config):
|
43
|
-
"""
|
44
|
-
Test getting default values for non-existent keys.
|
45
|
-
"""
|
46
|
-
# Non-existent key with default
|
47
|
-
assert test_config.get("non_existent", "default") == "default"
|
48
|
-
|
49
|
-
# Non-existent nested key with default
|
50
|
-
assert test_config.get("server.non_existent", 42) == 42
|
51
|
-
|
52
|
-
# Non-existent top level with nested key
|
53
|
-
assert test_config.get("non_existent.key", False) is False
|
54
|
-
|
55
|
-
|
56
|
-
def test_config_set_values(test_config):
|
57
|
-
"""
|
58
|
-
Test setting values in configuration.
|
59
|
-
"""
|
60
|
-
# Set top-level value
|
61
|
-
test_config.set("new_key", "value")
|
62
|
-
assert test_config.get("new_key") == "value"
|
63
|
-
|
64
|
-
# Set nested value for existing parent
|
65
|
-
test_config.set("server.api_key", "secret")
|
66
|
-
assert test_config.get("server.api_key") == "secret"
|
67
|
-
|
68
|
-
# Set nested value with non-existent parent
|
69
|
-
test_config.set("database.url", "postgres://localhost")
|
70
|
-
assert test_config.get("database.url") == "postgres://localhost"
|
71
|
-
|
72
|
-
# Overwrite existing value
|
73
|
-
test_config.set("server.host", "0.0.0.0")
|
74
|
-
assert test_config.get("server.host") == "0.0.0.0"
|
75
|
-
|
76
|
-
|
77
|
-
def test_config_save_load(temp_config_file):
|
78
|
-
"""
|
79
|
-
Test saving and loading configuration.
|
80
|
-
"""
|
81
|
-
# Create and modify config
|
82
|
-
config = Config(temp_config_file)
|
83
|
-
config.set("test_key", "test_value")
|
84
|
-
config.set("nested.key", 123)
|
85
|
-
|
86
|
-
# Save config
|
87
|
-
config.save()
|
88
|
-
|
89
|
-
# Create new config instance to load from the same file
|
90
|
-
new_config = Config(temp_config_file)
|
91
|
-
|
92
|
-
# Verify values were saved and loaded
|
93
|
-
assert new_config.get("test_key") == "test_value"
|
94
|
-
assert new_config.get("nested.key") == 123
|
95
|
-
assert new_config.get("server.host") == "127.0.0.1"
|
96
|
-
|
97
|
-
|
98
|
-
def test_config_environment_variables():
|
99
|
-
"""
|
100
|
-
Test environment variables override configuration values.
|
101
|
-
"""
|
102
|
-
with tempfile.NamedTemporaryFile(suffix=".json", delete=False, mode="w") as temp:
|
103
|
-
temp_path = temp.name
|
104
|
-
json.dump({"server": {"host": "localhost", "port": 8000}}, temp)
|
105
|
-
|
106
|
-
try:
|
107
|
-
# Set environment variables
|
108
|
-
os.environ["SERVICE_SERVER_HOST"] = "192.168.1.1"
|
109
|
-
os.environ["SERVICE_SERVER_PORT"] = "9000"
|
110
|
-
os.environ["SERVICE_LOGGING_LEVEL"] = "INFO"
|
111
|
-
|
112
|
-
# Create config that should load from env vars
|
113
|
-
config = Config(temp_path)
|
114
|
-
|
115
|
-
# Check values are overridden by environment
|
116
|
-
assert config.get("server.host") == "192.168.1.1"
|
117
|
-
assert config.get("server.port") == 9000
|
118
|
-
assert config.get("logging.level") == "INFO"
|
119
|
-
finally:
|
120
|
-
# Clean up
|
121
|
-
os.unlink(temp_path)
|
122
|
-
if "SERVICE_SERVER_HOST" in os.environ:
|
123
|
-
del os.environ["SERVICE_SERVER_HOST"]
|
124
|
-
if "SERVICE_SERVER_PORT" in os.environ:
|
125
|
-
del os.environ["SERVICE_SERVER_PORT"]
|
126
|
-
if "SERVICE_LOGGING_LEVEL" in os.environ:
|
127
|
-
del os.environ["SERVICE_LOGGING_LEVEL"]
|
@@ -1,65 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Test utilities for mcp_microservice.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import Any, Dict
|
6
|
-
from mcp_proxy_adapter.commands.result import CommandResult
|
7
|
-
|
8
|
-
|
9
|
-
class MockResult(CommandResult):
|
10
|
-
"""
|
11
|
-
Mock result class for testing.
|
12
|
-
|
13
|
-
Attributes:
|
14
|
-
message: Test message.
|
15
|
-
timestamp: Test timestamp.
|
16
|
-
"""
|
17
|
-
|
18
|
-
def __init__(self, message: str = "Test message", timestamp: float = 12345.0):
|
19
|
-
self.message = message
|
20
|
-
self.timestamp = timestamp
|
21
|
-
|
22
|
-
def to_dict(self) -> Dict[str, Any]:
|
23
|
-
"""
|
24
|
-
Converts result to dictionary for serialization.
|
25
|
-
|
26
|
-
Returns:
|
27
|
-
Dictionary with result data.
|
28
|
-
"""
|
29
|
-
return {
|
30
|
-
"message": self.message,
|
31
|
-
"timestamp": self.timestamp
|
32
|
-
}
|
33
|
-
|
34
|
-
@classmethod
|
35
|
-
def get_schema(cls) -> Dict[str, Any]:
|
36
|
-
"""
|
37
|
-
Returns JSON schema for result validation.
|
38
|
-
|
39
|
-
Returns:
|
40
|
-
Dictionary with JSON schema.
|
41
|
-
"""
|
42
|
-
return {
|
43
|
-
"type": "object",
|
44
|
-
"properties": {
|
45
|
-
"message": {"type": "string", "description": "Test message"},
|
46
|
-
"timestamp": {"type": "number", "description": "Test timestamp"}
|
47
|
-
},
|
48
|
-
"required": ["message", "timestamp"]
|
49
|
-
}
|
50
|
-
|
51
|
-
@classmethod
|
52
|
-
def from_dict(cls, data: Dict[str, Any]) -> "MockResult":
|
53
|
-
"""
|
54
|
-
Creates result instance from dictionary.
|
55
|
-
|
56
|
-
Args:
|
57
|
-
data: Dictionary with result data.
|
58
|
-
|
59
|
-
Returns:
|
60
|
-
MockResult instance.
|
61
|
-
"""
|
62
|
-
return cls(
|
63
|
-
message=data.get("message", ""),
|
64
|
-
timestamp=data.get("timestamp", 0.0)
|
65
|
-
)
|