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.
Files changed (259) hide show
  1. mcp_proxy_adapter/api/app.py +174 -80
  2. mcp_proxy_adapter/api/handlers.py +16 -5
  3. mcp_proxy_adapter/api/middleware/__init__.py +7 -2
  4. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  5. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  6. mcp_proxy_adapter/api/middleware/unified_security.py +152 -0
  7. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  8. mcp_proxy_adapter/commands/__init__.py +7 -1
  9. mcp_proxy_adapter/commands/base.py +7 -4
  10. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  11. mcp_proxy_adapter/commands/command_registry.py +8 -0
  12. mcp_proxy_adapter/commands/echo_command.py +81 -0
  13. mcp_proxy_adapter/commands/help_command.py +21 -14
  14. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  15. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  16. mcp_proxy_adapter/commands/security_command.py +488 -0
  17. mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
  18. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  19. mcp_proxy_adapter/config.py +81 -21
  20. mcp_proxy_adapter/core/app_factory.py +326 -0
  21. mcp_proxy_adapter/core/client_security.py +384 -0
  22. mcp_proxy_adapter/core/logging.py +8 -3
  23. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  24. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  25. mcp_proxy_adapter/core/protocol_manager.py +9 -0
  26. mcp_proxy_adapter/core/proxy_client.py +602 -0
  27. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  28. mcp_proxy_adapter/core/security_adapter.py +12 -15
  29. mcp_proxy_adapter/core/security_integration.py +277 -0
  30. mcp_proxy_adapter/core/server_adapter.py +345 -0
  31. mcp_proxy_adapter/core/server_engine.py +364 -0
  32. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  33. mcp_proxy_adapter/examples/README.md +230 -97
  34. mcp_proxy_adapter/examples/README_EN.md +258 -0
  35. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  36. mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
  37. mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
  38. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  39. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  40. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +39 -0
  41. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +25 -0
  42. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  43. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  44. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  45. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  46. mcp_proxy_adapter/examples/cert_config.json +9 -0
  47. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  48. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  49. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  50. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  51. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  52. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  53. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  54. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  55. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  56. mcp_proxy_adapter/examples/certs/client.key +52 -0
  57. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  58. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  59. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  60. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  61. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  62. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  63. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  64. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  65. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  66. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  67. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  68. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  69. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  70. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  71. mcp_proxy_adapter/examples/certs/server.key +52 -0
  72. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  73. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  74. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  75. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  76. mcp_proxy_adapter/examples/certs/user.key +52 -0
  77. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  78. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  79. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  80. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  81. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  82. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  83. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  84. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  85. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  86. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  87. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  88. mcp_proxy_adapter/examples/demo_client.py +341 -0
  89. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  90. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  91. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  92. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  93. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  94. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  95. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  96. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  99. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  100. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  102. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  103. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  104. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  105. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  106. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  107. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  108. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  109. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  110. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  111. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  112. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  124. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  125. mcp_proxy_adapter/examples/roles.json +38 -0
  126. mcp_proxy_adapter/examples/run_example.py +81 -0
  127. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  128. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  129. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  130. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  131. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  132. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  133. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  134. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  135. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  136. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  137. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  138. mcp_proxy_adapter/examples/test_examples.py +344 -0
  139. mcp_proxy_adapter/examples/universal_client.py +628 -0
  140. mcp_proxy_adapter/main.py +21 -10
  141. mcp_proxy_adapter/utils/config_generator.py +639 -0
  142. mcp_proxy_adapter/version.py +2 -1
  143. mcp_proxy_adapter-6.1.0.dist-info/METADATA +205 -0
  144. mcp_proxy_adapter-6.1.0.dist-info/RECORD +193 -0
  145. mcp_proxy_adapter-6.1.0.dist-info/entry_points.txt +2 -0
  146. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/licenses/LICENSE +2 -2
  147. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  148. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  149. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  150. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  151. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  152. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  153. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  154. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  155. mcp_proxy_adapter/api/middleware/security.py +0 -376
  156. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  157. mcp_proxy_adapter/examples/__init__.py +0 -7
  158. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  159. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  160. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  161. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  162. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  163. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  164. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  165. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  166. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  167. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  168. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  169. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  170. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  171. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  172. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  173. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  174. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  175. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  176. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  177. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  178. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  179. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  180. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  181. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  182. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  183. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  184. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  185. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  186. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  187. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  188. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  189. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  190. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  191. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  192. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  193. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  194. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  195. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  196. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  197. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  198. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  199. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  200. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  201. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  202. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  203. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  204. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  205. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  206. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  207. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  208. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  209. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  210. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  211. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  212. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  213. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  214. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  215. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  216. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  217. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  218. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  219. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  220. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  221. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  222. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  223. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  224. mcp_proxy_adapter/tests/__init__.py +0 -0
  225. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  226. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  227. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  228. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  229. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  230. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  231. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  232. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  233. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  234. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  235. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  236. mcp_proxy_adapter/tests/conftest.py +0 -131
  237. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  238. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  239. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  240. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  241. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  242. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  243. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  244. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  245. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  246. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  247. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  248. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  249. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  250. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  251. mcp_proxy_adapter/tests/test_config.py +0 -127
  252. mcp_proxy_adapter/tests/test_utils.py +0 -65
  253. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  254. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  255. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  256. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  257. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  258. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/WHEEL +0 -0
  259. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.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