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,253 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Functional tests for the API.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import pytest
|
6
|
-
from typing import Dict, Any
|
7
|
-
|
8
|
-
from fastapi.testclient import TestClient
|
9
|
-
|
10
|
-
from mcp_proxy_adapter.commands.command_registry import registry
|
11
|
-
from mcp_proxy_adapter.tests.stubs.echo_command import EchoCommand
|
12
|
-
|
13
|
-
|
14
|
-
@pytest.fixture
|
15
|
-
def register_echo_command(clean_registry):
|
16
|
-
"""
|
17
|
-
Fixture to register the Echo command for testing.
|
18
|
-
|
19
|
-
Args:
|
20
|
-
clean_registry: Fixture to clean registry before and after test.
|
21
|
-
"""
|
22
|
-
registry.register(EchoCommand)
|
23
|
-
yield
|
24
|
-
registry.clear()
|
25
|
-
|
26
|
-
|
27
|
-
@pytest.mark.functional
|
28
|
-
def test_execute_command(test_client: TestClient, json_rpc_request: Dict[str, Any], register_echo_command):
|
29
|
-
"""
|
30
|
-
Test execution of command via API.
|
31
|
-
|
32
|
-
Args:
|
33
|
-
test_client: FastAPI test client.
|
34
|
-
json_rpc_request: Base JSON-RPC request.
|
35
|
-
register_echo_command: Fixture to register test command.
|
36
|
-
"""
|
37
|
-
# Create JSON-RPC request
|
38
|
-
request_data = json_rpc_request.copy()
|
39
|
-
request_data["method"] = "echo"
|
40
|
-
request_data["params"] = {"test_key": "test_value"}
|
41
|
-
|
42
|
-
# Send request
|
43
|
-
response = test_client.post("/api/jsonrpc", json=request_data)
|
44
|
-
|
45
|
-
# Check response
|
46
|
-
assert response.status_code == 200
|
47
|
-
assert response.headers["content-type"] == "application/json"
|
48
|
-
|
49
|
-
# Check response structure
|
50
|
-
data = response.json()
|
51
|
-
assert "jsonrpc" in data and data["jsonrpc"] == "2.0"
|
52
|
-
assert "result" in data
|
53
|
-
assert "id" in data and data["id"] == request_data["id"]
|
54
|
-
|
55
|
-
# Check result content
|
56
|
-
assert "params" in data["result"]
|
57
|
-
assert data["result"]["params"] == {"test_key": "test_value"}
|
58
|
-
|
59
|
-
|
60
|
-
@pytest.mark.functional
|
61
|
-
def test_execute_nonexistent_command(test_client: TestClient, json_rpc_request: Dict[str, Any]):
|
62
|
-
"""
|
63
|
-
Test execution of nonexistent command.
|
64
|
-
|
65
|
-
Args:
|
66
|
-
test_client: FastAPI test client.
|
67
|
-
json_rpc_request: Base JSON-RPC request.
|
68
|
-
"""
|
69
|
-
# Create JSON-RPC request with nonexistent command
|
70
|
-
request_data = json_rpc_request.copy()
|
71
|
-
request_data["method"] = "nonexistent_command"
|
72
|
-
|
73
|
-
# Send request
|
74
|
-
response = test_client.post("/api/jsonrpc", json=request_data)
|
75
|
-
|
76
|
-
# Check response
|
77
|
-
assert response.status_code == 400 or response.status_code == 200
|
78
|
-
|
79
|
-
# Check response structure
|
80
|
-
data = response.json()
|
81
|
-
assert "jsonrpc" in data and data["jsonrpc"] == "2.0"
|
82
|
-
assert "error" in data
|
83
|
-
assert "id" in data and data["id"] == request_data["id"]
|
84
|
-
|
85
|
-
# Check error content
|
86
|
-
assert "code" in data["error"]
|
87
|
-
assert "message" in data["error"]
|
88
|
-
assert data["error"]["code"] == -32601 # Method not found
|
89
|
-
assert "not found" in data["error"]["message"].lower()
|
90
|
-
|
91
|
-
|
92
|
-
@pytest.mark.functional
|
93
|
-
def test_invalid_json_rpc_request(test_client: TestClient):
|
94
|
-
"""
|
95
|
-
Test invalid JSON-RPC request.
|
96
|
-
|
97
|
-
Args:
|
98
|
-
test_client: FastAPI test client.
|
99
|
-
"""
|
100
|
-
# Create invalid JSON-RPC request
|
101
|
-
request_data = {
|
102
|
-
"method": "echo",
|
103
|
-
"params": {}
|
104
|
-
# Missing jsonrpc and id fields
|
105
|
-
}
|
106
|
-
|
107
|
-
# Send request
|
108
|
-
response = test_client.post("/api/jsonrpc", json=request_data)
|
109
|
-
|
110
|
-
# Check response
|
111
|
-
assert response.status_code == 400 or response.status_code == 200
|
112
|
-
|
113
|
-
# Check response structure
|
114
|
-
data = response.json()
|
115
|
-
assert "jsonrpc" in data and data["jsonrpc"] == "2.0"
|
116
|
-
assert "error" in data
|
117
|
-
|
118
|
-
# Check error content
|
119
|
-
assert "code" in data["error"]
|
120
|
-
assert "message" in data["error"]
|
121
|
-
assert data["error"]["code"] == -32600 # Invalid Request
|
122
|
-
|
123
|
-
|
124
|
-
@pytest.mark.functional
|
125
|
-
def test_get_commands(test_client: TestClient, register_echo_command):
|
126
|
-
"""
|
127
|
-
Test getting list of commands.
|
128
|
-
|
129
|
-
Args:
|
130
|
-
test_client: FastAPI test client.
|
131
|
-
register_echo_command: Fixture to register test command.
|
132
|
-
"""
|
133
|
-
# Send request
|
134
|
-
response = test_client.get("/api/commands")
|
135
|
-
|
136
|
-
# Check response
|
137
|
-
assert response.status_code == 200
|
138
|
-
|
139
|
-
# Check response structure
|
140
|
-
data = response.json()
|
141
|
-
assert "commands" in data
|
142
|
-
assert isinstance(data["commands"], dict)
|
143
|
-
|
144
|
-
# Check that echo command is in the list
|
145
|
-
assert "echo" in data["commands"]
|
146
|
-
assert "description" in data["commands"]["echo"]
|
147
|
-
assert "schema" in data["commands"]["echo"]
|
148
|
-
|
149
|
-
|
150
|
-
@pytest.mark.functional
|
151
|
-
def test_health_check(test_client: TestClient):
|
152
|
-
"""
|
153
|
-
Test health check endpoint.
|
154
|
-
|
155
|
-
Args:
|
156
|
-
test_client: FastAPI test client.
|
157
|
-
"""
|
158
|
-
# Send request
|
159
|
-
response = test_client.get("/health")
|
160
|
-
|
161
|
-
# Check response
|
162
|
-
assert response.status_code == 200
|
163
|
-
|
164
|
-
# Check response structure
|
165
|
-
data = response.json()
|
166
|
-
assert "status" in data
|
167
|
-
assert data["status"] == "ok"
|
168
|
-
|
169
|
-
|
170
|
-
@pytest.mark.functional
|
171
|
-
def test_openapi_schema(test_client: TestClient):
|
172
|
-
"""
|
173
|
-
Test OpenAPI schema endpoint.
|
174
|
-
|
175
|
-
Args:
|
176
|
-
test_client: FastAPI test client.
|
177
|
-
"""
|
178
|
-
# Send request
|
179
|
-
response = test_client.get("/openapi.json")
|
180
|
-
|
181
|
-
# Check response
|
182
|
-
assert response.status_code == 200
|
183
|
-
|
184
|
-
# Check response content
|
185
|
-
data = response.json()
|
186
|
-
assert "openapi" in data
|
187
|
-
assert "info" in data
|
188
|
-
assert "paths" in data
|
189
|
-
|
190
|
-
# Check that API endpoints are in schema
|
191
|
-
assert "/cmd" in data["paths"]
|
192
|
-
assert "/api/commands" in data["paths"]
|
193
|
-
assert "/health" in data["paths"]
|
194
|
-
|
195
|
-
|
196
|
-
@pytest.mark.functional
|
197
|
-
def test_batch_requests(test_client: TestClient, json_rpc_request: Dict[str, Any], register_echo_command):
|
198
|
-
"""
|
199
|
-
Test batch requests processing.
|
200
|
-
|
201
|
-
Args:
|
202
|
-
test_client: FastAPI test client.
|
203
|
-
json_rpc_request: Base JSON-RPC request.
|
204
|
-
register_echo_command: Fixture to register test command.
|
205
|
-
"""
|
206
|
-
# Create batch request
|
207
|
-
request1 = json_rpc_request.copy()
|
208
|
-
request1["method"] = "echo"
|
209
|
-
request1["params"] = {"request_id": "1"}
|
210
|
-
request1["id"] = "1"
|
211
|
-
|
212
|
-
request2 = json_rpc_request.copy()
|
213
|
-
request2["method"] = "echo"
|
214
|
-
request2["params"] = {"request_id": "2"}
|
215
|
-
request2["id"] = "2"
|
216
|
-
|
217
|
-
batch_request = [request1, request2]
|
218
|
-
|
219
|
-
# Send request
|
220
|
-
response = test_client.post("/api/jsonrpc", json=batch_request)
|
221
|
-
|
222
|
-
# Check response
|
223
|
-
assert response.status_code == 200
|
224
|
-
|
225
|
-
# Check response structure
|
226
|
-
data = response.json()
|
227
|
-
assert isinstance(data, list)
|
228
|
-
assert len(data) == 2
|
229
|
-
|
230
|
-
# Check individual responses
|
231
|
-
assert data[0]["result"]["params"] == {"request_id": "1"}
|
232
|
-
assert data[0]["id"] == "1"
|
233
|
-
|
234
|
-
assert data[1]["result"]["params"] == {"request_id": "2"}
|
235
|
-
assert data[1]["id"] == "2"
|
236
|
-
|
237
|
-
|
238
|
-
def test_custom_openapi_schema_fields():
|
239
|
-
"""
|
240
|
-
Test that custom title, description, and version are set in the OpenAPI schema.
|
241
|
-
"""
|
242
|
-
from fastapi import FastAPI
|
243
|
-
from mcp_proxy_adapter.custom_openapi import custom_openapi
|
244
|
-
|
245
|
-
app = FastAPI(
|
246
|
-
title="Custom Title",
|
247
|
-
description="Custom Description",
|
248
|
-
version="9.9.9"
|
249
|
-
)
|
250
|
-
schema = custom_openapi(app)
|
251
|
-
assert schema["info"]["title"] == "Custom Title"
|
252
|
-
assert schema["info"]["description"] == "Custom Description"
|
253
|
-
assert schema["info"]["version"] == "9.9.9"
|
@@ -1,129 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Integration tests for /cmd endpoint and help command.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import pytest
|
6
|
-
from fastapi.testclient import TestClient
|
7
|
-
|
8
|
-
from mcp_proxy_adapter.api.app import app
|
9
|
-
from mcp_proxy_adapter.commands.command_registry import registry
|
10
|
-
from mcp_proxy_adapter.commands.help_command import HelpCommand
|
11
|
-
|
12
|
-
|
13
|
-
@pytest.fixture(autouse=True)
|
14
|
-
def setup_registry():
|
15
|
-
"""Setup command registry for tests."""
|
16
|
-
# Store original commands
|
17
|
-
original_commands = dict(registry._commands)
|
18
|
-
|
19
|
-
# Clear registry
|
20
|
-
registry._commands.clear()
|
21
|
-
|
22
|
-
# Register help command
|
23
|
-
registry.register(HelpCommand)
|
24
|
-
|
25
|
-
yield
|
26
|
-
|
27
|
-
# Restore original commands
|
28
|
-
registry._commands.clear()
|
29
|
-
for name, command in original_commands.items():
|
30
|
-
registry._commands[name] = command
|
31
|
-
|
32
|
-
|
33
|
-
@pytest.fixture
|
34
|
-
def client():
|
35
|
-
"""Test client for FastAPI app."""
|
36
|
-
return TestClient(app)
|
37
|
-
|
38
|
-
|
39
|
-
def test_cmd_help_without_params(client):
|
40
|
-
"""Test /cmd endpoint with help command without parameters."""
|
41
|
-
response = client.post(
|
42
|
-
"/cmd",
|
43
|
-
json={"command": "help"}
|
44
|
-
)
|
45
|
-
|
46
|
-
assert response.status_code == 200
|
47
|
-
assert "result" in response.json()
|
48
|
-
result = response.json()["result"]
|
49
|
-
|
50
|
-
assert "commands" in result
|
51
|
-
assert "help" in result["commands"]
|
52
|
-
assert "summary" in result["commands"]["help"]
|
53
|
-
|
54
|
-
|
55
|
-
def test_cmd_help_with_cmdname(client):
|
56
|
-
"""Test /cmd endpoint with help command with cmdname parameter."""
|
57
|
-
response = client.post(
|
58
|
-
"/cmd",
|
59
|
-
json={
|
60
|
-
"command": "help",
|
61
|
-
"params": {
|
62
|
-
"cmdname": "help"
|
63
|
-
}
|
64
|
-
}
|
65
|
-
)
|
66
|
-
|
67
|
-
assert response.status_code == 200
|
68
|
-
assert "result" in response.json()
|
69
|
-
result = response.json()["result"]
|
70
|
-
|
71
|
-
assert "cmdname" in result
|
72
|
-
assert result["cmdname"] == "help"
|
73
|
-
assert "info" in result
|
74
|
-
assert "description" in result["info"]
|
75
|
-
assert "params" in result["info"]
|
76
|
-
assert "cmdname" in result["info"]["params"]
|
77
|
-
|
78
|
-
|
79
|
-
def test_cmd_help_unknown_command(client):
|
80
|
-
"""Test /cmd endpoint with help command for unknown command."""
|
81
|
-
response = client.post(
|
82
|
-
"/cmd",
|
83
|
-
json={
|
84
|
-
"command": "help",
|
85
|
-
"params": {
|
86
|
-
"cmdname": "unknown_command"
|
87
|
-
}
|
88
|
-
}
|
89
|
-
)
|
90
|
-
|
91
|
-
assert response.status_code == 200
|
92
|
-
assert "result" in response.json()
|
93
|
-
result = response.json()["result"]
|
94
|
-
|
95
|
-
assert "error" in result
|
96
|
-
assert "example" in result
|
97
|
-
assert "note" in result
|
98
|
-
assert result["error"].startswith("Command")
|
99
|
-
assert result["example"]["command"] == "help"
|
100
|
-
|
101
|
-
|
102
|
-
def test_cmd_unknown_command(client):
|
103
|
-
"""Test /cmd endpoint with unknown command."""
|
104
|
-
response = client.post(
|
105
|
-
"/cmd",
|
106
|
-
json={"command": "unknown_command"}
|
107
|
-
)
|
108
|
-
|
109
|
-
assert response.status_code == 200
|
110
|
-
assert "error" in response.json()
|
111
|
-
error = response.json()["error"]
|
112
|
-
|
113
|
-
assert error["code"] == -32601
|
114
|
-
assert "не найдена" in error["message"]
|
115
|
-
|
116
|
-
|
117
|
-
def test_cmd_invalid_request(client):
|
118
|
-
"""Test /cmd endpoint with invalid request format."""
|
119
|
-
response = client.post(
|
120
|
-
"/cmd",
|
121
|
-
json={"invalid": "request"}
|
122
|
-
)
|
123
|
-
|
124
|
-
assert response.status_code == 200
|
125
|
-
assert "error" in response.json()
|
126
|
-
error = response.json()["error"]
|
127
|
-
|
128
|
-
assert error["code"] == -32600
|
129
|
-
assert "Отсутствует обязательное поле 'command'" in error["message"]
|
@@ -1,255 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Integration tests for the mcp_microservice package.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import pytest
|
6
|
-
import json
|
7
|
-
from typing import Dict, Any
|
8
|
-
|
9
|
-
from fastapi.testclient import TestClient
|
10
|
-
|
11
|
-
from mcp_proxy_adapter.commands.command_registry import registry
|
12
|
-
from mcp_proxy_adapter.tests.stubs.echo_command import EchoCommand
|
13
|
-
from mcp_proxy_adapter.api.app import create_app
|
14
|
-
from mcp_proxy_adapter.config import Config
|
15
|
-
|
16
|
-
|
17
|
-
@pytest.fixture
|
18
|
-
def integration_config():
|
19
|
-
"""
|
20
|
-
Fixture for integration test configuration.
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
Config instance for integration tests.
|
24
|
-
"""
|
25
|
-
config = Config()
|
26
|
-
# Загружаем тестовую конфигурацию
|
27
|
-
config._config = {
|
28
|
-
"server": {
|
29
|
-
"host": "127.0.0.1",
|
30
|
-
"port": 8889
|
31
|
-
},
|
32
|
-
"logging": {
|
33
|
-
"level": "DEBUG",
|
34
|
-
"file": None
|
35
|
-
},
|
36
|
-
"auth_enabled": False,
|
37
|
-
"rate_limit_enabled": False
|
38
|
-
}
|
39
|
-
return config
|
40
|
-
|
41
|
-
|
42
|
-
@pytest.fixture
|
43
|
-
def integration_app(integration_config):
|
44
|
-
"""
|
45
|
-
Fixture for integration test application.
|
46
|
-
|
47
|
-
Args:
|
48
|
-
integration_config: Configuration for integration tests.
|
49
|
-
|
50
|
-
Returns:
|
51
|
-
FastAPI application instance.
|
52
|
-
"""
|
53
|
-
return create_app()
|
54
|
-
|
55
|
-
|
56
|
-
@pytest.fixture
|
57
|
-
def integration_client(integration_app):
|
58
|
-
"""
|
59
|
-
Fixture for integration test client.
|
60
|
-
|
61
|
-
Args:
|
62
|
-
integration_app: FastAPI application for integration tests.
|
63
|
-
|
64
|
-
Returns:
|
65
|
-
FastAPI test client.
|
66
|
-
"""
|
67
|
-
return TestClient(integration_app)
|
68
|
-
|
69
|
-
|
70
|
-
@pytest.mark.integration
|
71
|
-
def test_command_registry_with_api(integration_client, clean_registry):
|
72
|
-
"""
|
73
|
-
Test integration between command registry and API.
|
74
|
-
|
75
|
-
Args:
|
76
|
-
integration_client: FastAPI test client.
|
77
|
-
clean_registry: Fixture to clean registry before and after test.
|
78
|
-
"""
|
79
|
-
# Register command
|
80
|
-
registry.register(EchoCommand)
|
81
|
-
|
82
|
-
# Create JSON-RPC request
|
83
|
-
request_data = {
|
84
|
-
"jsonrpc": "2.0",
|
85
|
-
"method": "echo",
|
86
|
-
"params": {"test_key": "test_value"},
|
87
|
-
"id": "test-id"
|
88
|
-
}
|
89
|
-
|
90
|
-
# Send request
|
91
|
-
response = integration_client.post("/api/jsonrpc", json=request_data)
|
92
|
-
|
93
|
-
# Check response
|
94
|
-
assert response.status_code == 200
|
95
|
-
|
96
|
-
# Check response structure
|
97
|
-
data = response.json()
|
98
|
-
assert "jsonrpc" in data and data["jsonrpc"] == "2.0"
|
99
|
-
assert "result" in data
|
100
|
-
assert "id" in data and data["id"] == request_data["id"]
|
101
|
-
|
102
|
-
# Check result content
|
103
|
-
assert "params" in data["result"]
|
104
|
-
assert data["result"]["params"] == {"test_key": "test_value"}
|
105
|
-
|
106
|
-
# Clean up
|
107
|
-
registry.clear()
|
108
|
-
|
109
|
-
|
110
|
-
@pytest.mark.integration
|
111
|
-
def test_command_execution_through_api(integration_client, clean_registry):
|
112
|
-
"""
|
113
|
-
Test command execution through API with complex parameters.
|
114
|
-
|
115
|
-
Args:
|
116
|
-
integration_client: FastAPI test client.
|
117
|
-
clean_registry: Fixture to clean registry before and after test.
|
118
|
-
"""
|
119
|
-
# Register command
|
120
|
-
registry.register(EchoCommand)
|
121
|
-
|
122
|
-
# Create JSON-RPC request with parameters
|
123
|
-
request_data = {
|
124
|
-
"jsonrpc": "2.0",
|
125
|
-
"method": "echo",
|
126
|
-
"params": {"complex_param": {"nested": "value", "array": [1, 2, 3]}},
|
127
|
-
"id": "test-id"
|
128
|
-
}
|
129
|
-
|
130
|
-
# Send request
|
131
|
-
response = integration_client.post("/api/jsonrpc", json=request_data)
|
132
|
-
|
133
|
-
# Check response
|
134
|
-
assert response.status_code == 200
|
135
|
-
|
136
|
-
# Check response content
|
137
|
-
data = response.json()
|
138
|
-
assert "params" in data["result"]
|
139
|
-
assert data["result"]["params"]["complex_param"]["nested"] == "value"
|
140
|
-
assert data["result"]["params"]["complex_param"]["array"] == [1, 2, 3]
|
141
|
-
|
142
|
-
# Clean up
|
143
|
-
registry.clear()
|
144
|
-
|
145
|
-
|
146
|
-
@pytest.mark.integration
|
147
|
-
def test_api_error_handling_with_command(integration_client, clean_registry):
|
148
|
-
"""
|
149
|
-
Test API error handling with command errors.
|
150
|
-
|
151
|
-
Args:
|
152
|
-
integration_client: FastAPI test client.
|
153
|
-
clean_registry: Fixture to clean registry before and after test.
|
154
|
-
"""
|
155
|
-
# Register command
|
156
|
-
registry.register(EchoCommand)
|
157
|
-
|
158
|
-
# Create JSON-RPC request with parameters
|
159
|
-
request_data = {
|
160
|
-
"jsonrpc": "2.0",
|
161
|
-
"method": "echo",
|
162
|
-
"params": {"test": "value"},
|
163
|
-
"id": "test-id"
|
164
|
-
}
|
165
|
-
|
166
|
-
# Send request
|
167
|
-
response = integration_client.post("/api/jsonrpc", json=request_data)
|
168
|
-
|
169
|
-
# Check response
|
170
|
-
assert response.status_code == 200
|
171
|
-
|
172
|
-
# Clean up
|
173
|
-
registry.clear()
|
174
|
-
|
175
|
-
|
176
|
-
@pytest.mark.integration
|
177
|
-
def test_api_commands_endpoint_with_registry(integration_client, clean_registry):
|
178
|
-
"""
|
179
|
-
Test API commands endpoint with loaded registry.
|
180
|
-
|
181
|
-
Args:
|
182
|
-
integration_client: FastAPI test client.
|
183
|
-
clean_registry: Fixture to clean registry before and after test.
|
184
|
-
"""
|
185
|
-
# Register command
|
186
|
-
registry.register(EchoCommand)
|
187
|
-
|
188
|
-
# Get commands list
|
189
|
-
response = integration_client.get("/api/commands")
|
190
|
-
|
191
|
-
# Check response
|
192
|
-
assert response.status_code == 200
|
193
|
-
|
194
|
-
# Check response structure
|
195
|
-
data = response.json()
|
196
|
-
assert "commands" in data
|
197
|
-
assert isinstance(data["commands"], dict)
|
198
|
-
|
199
|
-
# Check that echo command is in the list
|
200
|
-
assert "echo" in data["commands"]
|
201
|
-
assert "description" in data["commands"]["echo"]
|
202
|
-
|
203
|
-
# Clean up
|
204
|
-
registry.clear()
|
205
|
-
|
206
|
-
|
207
|
-
@pytest.mark.integration
|
208
|
-
def test_batch_requests_integration(integration_client, clean_registry):
|
209
|
-
"""
|
210
|
-
Test batch requests processing.
|
211
|
-
|
212
|
-
Args:
|
213
|
-
integration_client: FastAPI test client.
|
214
|
-
clean_registry: Fixture to clean registry before and after test.
|
215
|
-
"""
|
216
|
-
# Register command
|
217
|
-
registry.register(EchoCommand)
|
218
|
-
|
219
|
-
# Create batch request
|
220
|
-
batch_request = [
|
221
|
-
{
|
222
|
-
"jsonrpc": "2.0",
|
223
|
-
"method": "echo",
|
224
|
-
"params": {"request_id": "1"},
|
225
|
-
"id": "1"
|
226
|
-
},
|
227
|
-
{
|
228
|
-
"jsonrpc": "2.0",
|
229
|
-
"method": "echo",
|
230
|
-
"params": {"request_id": "2"},
|
231
|
-
"id": "2"
|
232
|
-
}
|
233
|
-
]
|
234
|
-
|
235
|
-
# Send request
|
236
|
-
response = integration_client.post("/api/jsonrpc", json=batch_request)
|
237
|
-
|
238
|
-
# Check response
|
239
|
-
assert response.status_code == 200
|
240
|
-
|
241
|
-
# Check response structure
|
242
|
-
data = response.json()
|
243
|
-
assert isinstance(data, list)
|
244
|
-
assert len(data) == 2
|
245
|
-
|
246
|
-
# Check individual responses
|
247
|
-
for i, resp in enumerate(data):
|
248
|
-
assert "jsonrpc" in resp and resp["jsonrpc"] == "2.0"
|
249
|
-
assert "result" in resp
|
250
|
-
assert "params" in resp["result"]
|
251
|
-
assert resp["result"]["params"]["request_id"] == str(i + 1)
|
252
|
-
assert resp["id"] == str(i + 1)
|
253
|
-
|
254
|
-
# Clean up
|
255
|
-
registry.clear()
|