mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.1.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/api/app.py +174 -80
- mcp_proxy_adapter/api/handlers.py +16 -5
- mcp_proxy_adapter/api/middleware/__init__.py +9 -4
- 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/protocol_middleware.py +32 -13
- mcp_proxy_adapter/api/middleware/unified_security.py +160 -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 +139 -8
- 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 +285 -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/docs/EN/TROUBLESHOOTING.md +285 -0
- mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +285 -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/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 +43 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +36 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +29 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +34 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +35 -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_config_generator.py +110 -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 +727 -0
- mcp_proxy_adapter/version.py +5 -2
- mcp_proxy_adapter-6.1.1.dist-info/METADATA +205 -0
- mcp_proxy_adapter-6.1.1.dist-info/RECORD +197 -0
- mcp_proxy_adapter-6.1.1.dist-info/entry_points.txt +2 -0
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.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.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/top_level.txt +0 -0
@@ -1,289 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tests for API handlers.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import json
|
6
|
-
import pytest
|
7
|
-
from typing import Dict, Any
|
8
|
-
from unittest.mock import AsyncMock, patch, MagicMock
|
9
|
-
|
10
|
-
from mcp_proxy_adapter.api.handlers import (
|
11
|
-
execute_command, handle_json_rpc, handle_batch_json_rpc,
|
12
|
-
get_server_health, get_commands_list
|
13
|
-
)
|
14
|
-
from mcp_proxy_adapter.commands.result import SuccessResult, ErrorResult
|
15
|
-
from mcp_proxy_adapter.tests.stubs.echo_command import EchoResult
|
16
|
-
from mcp_proxy_adapter.core.errors import (
|
17
|
-
ValidationError, CommandError, NotFoundError, MethodNotFoundError,
|
18
|
-
InvalidRequestError, ParseError, InternalError
|
19
|
-
)
|
20
|
-
|
21
|
-
|
22
|
-
@pytest.fixture
|
23
|
-
def success_result():
|
24
|
-
"""Fixture for test success result."""
|
25
|
-
result = SuccessResult(data={"key": "value"}, message="Success")
|
26
|
-
return result
|
27
|
-
|
28
|
-
|
29
|
-
@pytest.fixture
|
30
|
-
def error_result():
|
31
|
-
"""Fixture for test error result."""
|
32
|
-
result = ErrorResult(message="Error message", code=400)
|
33
|
-
return result
|
34
|
-
|
35
|
-
|
36
|
-
class TestExecuteCommand:
|
37
|
-
"""Tests for execute_command function."""
|
38
|
-
|
39
|
-
@pytest.mark.asyncio
|
40
|
-
async def test_execute_command_success(self):
|
41
|
-
"""Test successful command execution."""
|
42
|
-
# Mock successful result
|
43
|
-
mock_result = EchoResult(params={"test_key": "test_value"})
|
44
|
-
|
45
|
-
# Mock command class and registry
|
46
|
-
with patch("mcp_proxy_adapter.commands.command_registry.registry.get_command") as mock_get_command:
|
47
|
-
# Создаем асинхронную mock-функцию
|
48
|
-
mock_run = AsyncMock(return_value=mock_result)
|
49
|
-
mock_command_class = MagicMock()
|
50
|
-
# Присваиваем асинхронную функцию методу run
|
51
|
-
mock_command_class.run = mock_run
|
52
|
-
mock_get_command.return_value = mock_command_class
|
53
|
-
|
54
|
-
# Execute command
|
55
|
-
result = await execute_command("test_command", {"param": "value"})
|
56
|
-
|
57
|
-
# Assert command was called correctly
|
58
|
-
mock_get_command.assert_called_once_with("test_command")
|
59
|
-
mock_run.assert_called_once_with(param="value")
|
60
|
-
|
61
|
-
# Assert result is as expected
|
62
|
-
assert result == mock_result.to_dict()
|
63
|
-
|
64
|
-
@pytest.mark.asyncio
|
65
|
-
async def test_execute_command_not_found(self):
|
66
|
-
"""Test command not found error."""
|
67
|
-
# Mock registry raising NotFoundError
|
68
|
-
with patch("mcp_proxy_adapter.commands.command_registry.registry.get_command") as mock_get_command:
|
69
|
-
mock_get_command.side_effect = NotFoundError("Command not found")
|
70
|
-
|
71
|
-
# Execute command and expect MethodNotFoundError
|
72
|
-
with pytest.raises(MethodNotFoundError) as exc_info:
|
73
|
-
await execute_command("unknown_command", {})
|
74
|
-
|
75
|
-
# Check error message
|
76
|
-
assert "Method not found" in str(exc_info.value)
|
77
|
-
|
78
|
-
@pytest.mark.asyncio
|
79
|
-
async def test_execute_command_internal_error(self):
|
80
|
-
"""Test internal error during command execution."""
|
81
|
-
# Mock registry raising an unexpected error
|
82
|
-
with patch("mcp_proxy_adapter.commands.command_registry.registry.get_command") as mock_get_command:
|
83
|
-
mock_get_command.side_effect = Exception("Unexpected error")
|
84
|
-
|
85
|
-
# Execute command and expect InternalError
|
86
|
-
with pytest.raises(InternalError) as exc_info:
|
87
|
-
await execute_command("test_command", {})
|
88
|
-
|
89
|
-
# Check error details
|
90
|
-
assert "Error executing command" in str(exc_info.value)
|
91
|
-
assert "original_error" in exc_info.value.data
|
92
|
-
|
93
|
-
|
94
|
-
class TestHandleJsonRpc:
|
95
|
-
"""Tests for handle_json_rpc function."""
|
96
|
-
|
97
|
-
@pytest.mark.asyncio
|
98
|
-
async def test_handle_json_rpc_success(self):
|
99
|
-
"""Test successful JSON-RPC request handling."""
|
100
|
-
# Mock execute_command
|
101
|
-
with patch("mcp_proxy_adapter.api.handlers.execute_command") as mock_execute:
|
102
|
-
# AsyncMock для асинхронной функции
|
103
|
-
mock_execute.return_value = {"result": "success"}
|
104
|
-
|
105
|
-
# Create request data
|
106
|
-
request_data = {
|
107
|
-
"jsonrpc": "2.0",
|
108
|
-
"method": "test_command",
|
109
|
-
"params": {"param": "value"},
|
110
|
-
"id": 123
|
111
|
-
}
|
112
|
-
|
113
|
-
# Handle request
|
114
|
-
response = await handle_json_rpc(request_data)
|
115
|
-
|
116
|
-
# Assert command was executed
|
117
|
-
mock_execute.assert_called_once_with("test_command", {"param": "value"}, None)
|
118
|
-
|
119
|
-
# Assert response format
|
120
|
-
assert response["jsonrpc"] == "2.0"
|
121
|
-
assert response["result"] == {"result": "success"}
|
122
|
-
assert response["id"] == 123
|
123
|
-
|
124
|
-
@pytest.mark.asyncio
|
125
|
-
async def test_handle_json_rpc_invalid_version(self):
|
126
|
-
"""Test invalid JSON-RPC version."""
|
127
|
-
# Create request with invalid version
|
128
|
-
request_data = {
|
129
|
-
"jsonrpc": "1.0",
|
130
|
-
"method": "test_command",
|
131
|
-
"id": 123
|
132
|
-
}
|
133
|
-
|
134
|
-
# Handle request
|
135
|
-
response = await handle_json_rpc(request_data)
|
136
|
-
|
137
|
-
# Assert error response
|
138
|
-
assert response["jsonrpc"] == "2.0"
|
139
|
-
assert response["error"]["code"] == -32600
|
140
|
-
assert "Invalid Request" in response["error"]["message"]
|
141
|
-
assert response["id"] == 123
|
142
|
-
|
143
|
-
@pytest.mark.asyncio
|
144
|
-
async def test_handle_json_rpc_missing_method(self):
|
145
|
-
"""Test missing method in JSON-RPC request."""
|
146
|
-
# Create request with missing method
|
147
|
-
request_data = {
|
148
|
-
"jsonrpc": "2.0",
|
149
|
-
"params": {},
|
150
|
-
"id": 123
|
151
|
-
}
|
152
|
-
|
153
|
-
# Handle request
|
154
|
-
response = await handle_json_rpc(request_data)
|
155
|
-
|
156
|
-
# Assert error response
|
157
|
-
assert response["jsonrpc"] == "2.0"
|
158
|
-
assert response["error"]["code"] == -32600
|
159
|
-
assert "Method is required" in response["error"]["message"]
|
160
|
-
assert response["id"] == 123
|
161
|
-
|
162
|
-
@pytest.mark.asyncio
|
163
|
-
async def test_handle_json_rpc_microservice_error(self):
|
164
|
-
"""Test microservice error during command execution."""
|
165
|
-
# Mock execute_command raising MicroserviceError
|
166
|
-
with patch("mcp_proxy_adapter.api.handlers.execute_command") as mock_execute:
|
167
|
-
mock_execute.side_effect = CommandError("Command failed", data={"reason": "test"})
|
168
|
-
|
169
|
-
# Create request data
|
170
|
-
request_data = {
|
171
|
-
"jsonrpc": "2.0",
|
172
|
-
"method": "test_command",
|
173
|
-
"params": {},
|
174
|
-
"id": 123
|
175
|
-
}
|
176
|
-
|
177
|
-
# Handle request
|
178
|
-
response = await handle_json_rpc(request_data)
|
179
|
-
|
180
|
-
# Assert error response
|
181
|
-
assert response["jsonrpc"] == "2.0"
|
182
|
-
assert response["error"]["code"] == -32000
|
183
|
-
assert "Command failed" in response["error"]["message"]
|
184
|
-
assert response["error"]["data"]["reason"] == "test"
|
185
|
-
assert response["id"] == 123
|
186
|
-
|
187
|
-
@pytest.mark.asyncio
|
188
|
-
async def test_handle_json_rpc_unhandled_error(self):
|
189
|
-
"""Test unhandled error during command execution."""
|
190
|
-
# Mock execute_command raising unexpected error
|
191
|
-
with patch("mcp_proxy_adapter.api.handlers.execute_command") as mock_execute:
|
192
|
-
mock_execute.side_effect = Exception("Unexpected error")
|
193
|
-
|
194
|
-
# Create request data
|
195
|
-
request_data = {
|
196
|
-
"jsonrpc": "2.0",
|
197
|
-
"method": "test_command",
|
198
|
-
"params": {},
|
199
|
-
"id": 123
|
200
|
-
}
|
201
|
-
|
202
|
-
# Handle request
|
203
|
-
response = await handle_json_rpc(request_data)
|
204
|
-
|
205
|
-
# Assert error response
|
206
|
-
assert response["jsonrpc"] == "2.0"
|
207
|
-
assert response["error"]["code"] == -32603
|
208
|
-
assert "Internal error" in response["error"]["message"]
|
209
|
-
assert "Unexpected error" in response["error"]["data"]["error"]
|
210
|
-
assert response["id"] == 123
|
211
|
-
|
212
|
-
|
213
|
-
class TestHandleBatchJsonRpc:
|
214
|
-
"""Tests for handle_batch_json_rpc function."""
|
215
|
-
|
216
|
-
@pytest.mark.asyncio
|
217
|
-
async def test_handle_batch_json_rpc(self):
|
218
|
-
"""Test batch JSON-RPC request handling."""
|
219
|
-
# Mock handle_json_rpc
|
220
|
-
with patch("mcp_proxy_adapter.api.handlers.handle_json_rpc") as mock_handle:
|
221
|
-
# AsyncMock для асинхронных результатов
|
222
|
-
mock_handle.side_effect = [
|
223
|
-
{"jsonrpc": "2.0", "result": "result1", "id": 1},
|
224
|
-
{"jsonrpc": "2.0", "result": "result2", "id": 2}
|
225
|
-
]
|
226
|
-
|
227
|
-
# Create batch request
|
228
|
-
batch_requests = [
|
229
|
-
{"jsonrpc": "2.0", "method": "method1", "id": 1},
|
230
|
-
{"jsonrpc": "2.0", "method": "method2", "id": 2}
|
231
|
-
]
|
232
|
-
|
233
|
-
# Handle batch request
|
234
|
-
responses = await handle_batch_json_rpc(batch_requests)
|
235
|
-
|
236
|
-
# Assert responses
|
237
|
-
assert len(responses) == 2
|
238
|
-
assert responses[0]["result"] == "result1"
|
239
|
-
assert responses[1]["result"] == "result2"
|
240
|
-
|
241
|
-
|
242
|
-
class TestGetServerHealth:
|
243
|
-
"""Tests for get_server_health function."""
|
244
|
-
|
245
|
-
@pytest.mark.asyncio
|
246
|
-
async def test_get_server_health(self):
|
247
|
-
"""Test getting server health information."""
|
248
|
-
# Call server health function
|
249
|
-
result = await get_server_health()
|
250
|
-
|
251
|
-
# Check basic structure and keys
|
252
|
-
assert "status" in result
|
253
|
-
assert result["status"] == "ok"
|
254
|
-
assert "version" in result
|
255
|
-
assert "uptime" in result
|
256
|
-
assert "components" in result
|
257
|
-
assert "system" in result["components"]
|
258
|
-
assert "process" in result["components"]
|
259
|
-
assert "commands" in result["components"]
|
260
|
-
|
261
|
-
|
262
|
-
class TestGetCommandsList:
|
263
|
-
"""Tests for get_commands_list function."""
|
264
|
-
|
265
|
-
@pytest.mark.asyncio
|
266
|
-
async def test_get_commands_list(self):
|
267
|
-
"""Test getting commands list."""
|
268
|
-
# Mock registry.get_all_commands
|
269
|
-
with patch("mcp_proxy_adapter.commands.command_registry.registry.get_all_commands") as mock_get_all:
|
270
|
-
# Create mock command class
|
271
|
-
mock_command = MagicMock()
|
272
|
-
mock_command.get_schema.return_value = {
|
273
|
-
"type": "object",
|
274
|
-
"description": "Test command description"
|
275
|
-
}
|
276
|
-
|
277
|
-
# Setup mock to return test commands
|
278
|
-
mock_get_all.return_value = {
|
279
|
-
"test_command": mock_command
|
280
|
-
}
|
281
|
-
|
282
|
-
# Call get_commands_list
|
283
|
-
result = await get_commands_list()
|
284
|
-
|
285
|
-
# Check result structure
|
286
|
-
assert "test_command" in result
|
287
|
-
assert result["test_command"]["name"] == "test_command"
|
288
|
-
assert result["test_command"]["description"] == "Test command description"
|
289
|
-
assert result["test_command"]["schema"]["type"] == "object"
|
@@ -1,123 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tests for command base classes.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import pytest
|
6
|
-
from typing import Dict, Any
|
7
|
-
|
8
|
-
from mcp_proxy_adapter.commands.base import Command
|
9
|
-
from mcp_proxy_adapter.commands.result import CommandResult, SuccessResult, ErrorResult
|
10
|
-
|
11
|
-
|
12
|
-
class MockResultClass(CommandResult):
|
13
|
-
"""Test result class for testing."""
|
14
|
-
|
15
|
-
def __init__(self, value: str):
|
16
|
-
self.value = value
|
17
|
-
|
18
|
-
def to_dict(self) -> Dict[str, Any]:
|
19
|
-
return {"value": self.value}
|
20
|
-
|
21
|
-
@classmethod
|
22
|
-
def get_schema(cls) -> Dict[str, Any]:
|
23
|
-
return {
|
24
|
-
"type": "object",
|
25
|
-
"properties": {
|
26
|
-
"value": {"type": "string"}
|
27
|
-
},
|
28
|
-
"required": ["value"]
|
29
|
-
}
|
30
|
-
|
31
|
-
|
32
|
-
class MockCommand(Command):
|
33
|
-
"""Test command for testing."""
|
34
|
-
|
35
|
-
name = "test_command"
|
36
|
-
result_class = MockResultClass
|
37
|
-
|
38
|
-
async def execute(self, value: str = "default") -> MockResultClass:
|
39
|
-
return MockResultClass(value)
|
40
|
-
|
41
|
-
@classmethod
|
42
|
-
def get_schema(cls) -> Dict[str, Any]:
|
43
|
-
return {
|
44
|
-
"type": "object",
|
45
|
-
"properties": {
|
46
|
-
"value": {"type": "string"}
|
47
|
-
},
|
48
|
-
"additionalProperties": False
|
49
|
-
}
|
50
|
-
|
51
|
-
|
52
|
-
def test_success_result():
|
53
|
-
"""Test success result class."""
|
54
|
-
result = SuccessResult(data={"key": "value"}, message="success message")
|
55
|
-
|
56
|
-
# Test to_dict method
|
57
|
-
result_dict = result.to_dict()
|
58
|
-
assert result_dict["success"] is True
|
59
|
-
assert result_dict["data"] == {"key": "value"}
|
60
|
-
assert result_dict["message"] == "success message"
|
61
|
-
|
62
|
-
# Test from_dict method
|
63
|
-
result2 = SuccessResult.from_dict(result_dict)
|
64
|
-
assert result2.data == {"key": "value"}
|
65
|
-
assert result2.message == "success message"
|
66
|
-
|
67
|
-
|
68
|
-
def test_error_result():
|
69
|
-
"""Test error result class."""
|
70
|
-
result = ErrorResult(message="error message", code=400, details={"field": "invalid"})
|
71
|
-
|
72
|
-
# Test to_dict method
|
73
|
-
result_dict = result.to_dict()
|
74
|
-
assert result_dict["success"] is False
|
75
|
-
assert result_dict["error"]["code"] == 400
|
76
|
-
assert result_dict["error"]["message"] == "error message"
|
77
|
-
assert result_dict["error"]["data"] == {"field": "invalid"}
|
78
|
-
|
79
|
-
# Test from_dict method
|
80
|
-
result2 = ErrorResult.from_dict(result_dict)
|
81
|
-
assert result2.message == "error message"
|
82
|
-
assert result2.code == 400
|
83
|
-
assert result2.details == {"field": "invalid"}
|
84
|
-
|
85
|
-
|
86
|
-
class CommandClassTests:
|
87
|
-
"""Test command class."""
|
88
|
-
|
89
|
-
@pytest.mark.asyncio
|
90
|
-
async def test_execute(self):
|
91
|
-
"""Test execute method."""
|
92
|
-
command = MockCommand()
|
93
|
-
result = await command.execute(value="test_value")
|
94
|
-
assert isinstance(result, MockResultClass)
|
95
|
-
assert result.value == "test_value"
|
96
|
-
|
97
|
-
@pytest.mark.asyncio
|
98
|
-
async def test_run(self):
|
99
|
-
"""Test run method (with validation)."""
|
100
|
-
result = await MockCommand.run(value="test_value")
|
101
|
-
assert isinstance(result, MockResultClass)
|
102
|
-
assert result.value == "test_value"
|
103
|
-
|
104
|
-
def test_get_schema(self):
|
105
|
-
"""Test get_schema method."""
|
106
|
-
schema = MockCommand.get_schema()
|
107
|
-
assert schema["type"] == "object"
|
108
|
-
assert "value" in schema["properties"]
|
109
|
-
assert schema["additionalProperties"] is False
|
110
|
-
|
111
|
-
def test_get_result_schema(self):
|
112
|
-
"""Test get_result_schema method."""
|
113
|
-
schema = MockCommand.get_result_schema()
|
114
|
-
assert schema["type"] == "object"
|
115
|
-
assert "value" in schema["properties"]
|
116
|
-
assert "value" in schema["required"]
|
117
|
-
|
118
|
-
def test_get_param_info(self):
|
119
|
-
"""Test get_param_info method."""
|
120
|
-
params = MockCommand.get_param_info()
|
121
|
-
assert "value" in params
|
122
|
-
assert params["value"]["required"] is False
|
123
|
-
assert params["value"]["default"] == "default"
|
@@ -1,117 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tests for JSON-RPC batch requests handling.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import pytest
|
6
|
-
from typing import Dict, Any, List
|
7
|
-
from unittest.mock import AsyncMock, patch, MagicMock
|
8
|
-
|
9
|
-
from mcp_proxy_adapter.api.handlers import handle_json_rpc, handle_batch_json_rpc
|
10
|
-
from mcp_proxy_adapter.commands.result import SuccessResult
|
11
|
-
from mcp_proxy_adapter.core.errors import NotFoundError, MicroserviceError
|
12
|
-
|
13
|
-
|
14
|
-
@pytest.fixture
|
15
|
-
def success_result():
|
16
|
-
"""Fixture for test success result."""
|
17
|
-
result = SuccessResult(data={"key": "value"}, message="Success")
|
18
|
-
return result
|
19
|
-
|
20
|
-
|
21
|
-
class TestBatchJsonRpc:
|
22
|
-
"""Tests for JSON-RPC batch requests handling."""
|
23
|
-
|
24
|
-
@pytest.mark.asyncio
|
25
|
-
@patch("mcp_proxy_adapter.api.handlers.handle_json_rpc")
|
26
|
-
async def test_batch_request_processing(self, mock_handle_json_rpc):
|
27
|
-
"""Test handling of batch requests."""
|
28
|
-
# Setup handle_json_rpc mock to return different responses
|
29
|
-
mock_handle_json_rpc.side_effect = [
|
30
|
-
# First request - success
|
31
|
-
{
|
32
|
-
"jsonrpc": "2.0",
|
33
|
-
"result": {"key1": "value1"},
|
34
|
-
"id": "1"
|
35
|
-
},
|
36
|
-
# Second request - error
|
37
|
-
{
|
38
|
-
"jsonrpc": "2.0",
|
39
|
-
"error": {
|
40
|
-
"code": -32601,
|
41
|
-
"message": "Method not found"
|
42
|
-
},
|
43
|
-
"id": "2"
|
44
|
-
},
|
45
|
-
# Third request - success
|
46
|
-
{
|
47
|
-
"jsonrpc": "2.0",
|
48
|
-
"result": {"key3": "value3"},
|
49
|
-
"id": "3"
|
50
|
-
}
|
51
|
-
]
|
52
|
-
|
53
|
-
# Create batch request
|
54
|
-
batch_request = [
|
55
|
-
{"jsonrpc": "2.0", "method": "method1", "params": {"p1": "v1"}, "id": "1"},
|
56
|
-
{"jsonrpc": "2.0", "method": "non_existent", "id": "2"},
|
57
|
-
{"jsonrpc": "2.0", "method": "method3", "params": {"p3": "v3"}, "id": "3"}
|
58
|
-
]
|
59
|
-
|
60
|
-
# Process batch request
|
61
|
-
responses = await handle_batch_json_rpc(batch_request)
|
62
|
-
|
63
|
-
# Assertions
|
64
|
-
assert len(responses) == 3
|
65
|
-
assert mock_handle_json_rpc.call_count == 3
|
66
|
-
|
67
|
-
# Check first response
|
68
|
-
assert responses[0]["jsonrpc"] == "2.0"
|
69
|
-
assert responses[0]["result"] == {"key1": "value1"}
|
70
|
-
assert responses[0]["id"] == "1"
|
71
|
-
|
72
|
-
# Check second response (error)
|
73
|
-
assert responses[1]["jsonrpc"] == "2.0"
|
74
|
-
assert responses[1]["error"]["code"] == -32601
|
75
|
-
assert responses[1]["id"] == "2"
|
76
|
-
|
77
|
-
# Check third response
|
78
|
-
assert responses[2]["jsonrpc"] == "2.0"
|
79
|
-
assert responses[2]["result"] == {"key3": "value3"}
|
80
|
-
assert responses[2]["id"] == "3"
|
81
|
-
|
82
|
-
@pytest.mark.asyncio
|
83
|
-
@patch("mcp_proxy_adapter.api.handlers.handle_json_rpc")
|
84
|
-
async def test_empty_batch_request(self, mock_handle_json_rpc):
|
85
|
-
"""Test handling of empty batch request."""
|
86
|
-
# Create empty batch request
|
87
|
-
batch_request = []
|
88
|
-
|
89
|
-
# Process batch request
|
90
|
-
responses = await handle_batch_json_rpc(batch_request)
|
91
|
-
|
92
|
-
# Assertions
|
93
|
-
assert len(responses) == 0
|
94
|
-
assert mock_handle_json_rpc.call_count == 0
|
95
|
-
|
96
|
-
@pytest.mark.asyncio
|
97
|
-
@patch("mcp_proxy_adapter.api.handlers.execute_command")
|
98
|
-
async def test_end_to_end_batch_processing(self, mock_execute_command, success_result):
|
99
|
-
"""Test end-to-end processing of batch requests."""
|
100
|
-
# Setup execute_command mock
|
101
|
-
mock_execute_command.return_value = success_result.to_dict()
|
102
|
-
|
103
|
-
# Create batch request
|
104
|
-
batch_request = [
|
105
|
-
{"jsonrpc": "2.0", "method": "method1", "params": {"p1": "v1"}, "id": "1"},
|
106
|
-
{"jsonrpc": "2.0", "method": "method2", "params": {"p2": "v2"}, "id": "2"}
|
107
|
-
]
|
108
|
-
|
109
|
-
# Process batch request
|
110
|
-
responses = await handle_batch_json_rpc(batch_request)
|
111
|
-
|
112
|
-
# Assertions
|
113
|
-
assert len(responses) == 2
|
114
|
-
for response in responses:
|
115
|
-
assert response["jsonrpc"] == "2.0"
|
116
|
-
assert "result" in response
|
117
|
-
assert "error" not in response
|