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.
Files changed (264) 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 +9 -4
  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/protocol_middleware.py +32 -13
  7. mcp_proxy_adapter/api/middleware/unified_security.py +160 -0
  8. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  9. mcp_proxy_adapter/commands/__init__.py +7 -1
  10. mcp_proxy_adapter/commands/base.py +7 -4
  11. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  12. mcp_proxy_adapter/commands/command_registry.py +8 -0
  13. mcp_proxy_adapter/commands/echo_command.py +81 -0
  14. mcp_proxy_adapter/commands/help_command.py +21 -14
  15. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  16. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  17. mcp_proxy_adapter/commands/security_command.py +488 -0
  18. mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
  19. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  20. mcp_proxy_adapter/config.py +81 -21
  21. mcp_proxy_adapter/core/app_factory.py +326 -0
  22. mcp_proxy_adapter/core/client_security.py +384 -0
  23. mcp_proxy_adapter/core/logging.py +8 -3
  24. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  25. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  26. mcp_proxy_adapter/core/protocol_manager.py +139 -8
  27. mcp_proxy_adapter/core/proxy_client.py +602 -0
  28. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  29. mcp_proxy_adapter/core/security_adapter.py +12 -15
  30. mcp_proxy_adapter/core/security_integration.py +285 -0
  31. mcp_proxy_adapter/core/server_adapter.py +345 -0
  32. mcp_proxy_adapter/core/server_engine.py +364 -0
  33. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  34. mcp_proxy_adapter/docs/EN/TROUBLESHOOTING.md +285 -0
  35. mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +285 -0
  36. mcp_proxy_adapter/examples/README.md +230 -97
  37. mcp_proxy_adapter/examples/README_EN.md +258 -0
  38. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  39. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  40. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  41. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +43 -0
  42. mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +36 -0
  43. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +29 -0
  44. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +34 -0
  45. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  46. mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +35 -0
  47. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  48. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  49. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  50. mcp_proxy_adapter/examples/cert_config.json +9 -0
  51. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  52. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  53. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  54. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  55. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  56. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  57. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  58. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  59. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  60. mcp_proxy_adapter/examples/certs/client.key +52 -0
  61. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  62. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  63. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  64. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  65. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  66. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  67. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  68. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  69. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  70. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  71. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  72. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  73. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  74. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  75. mcp_proxy_adapter/examples/certs/server.key +52 -0
  76. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  77. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  78. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  79. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  80. mcp_proxy_adapter/examples/certs/user.key +52 -0
  81. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  82. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  83. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  84. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  85. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  86. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  87. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  88. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  89. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  90. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  91. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  92. mcp_proxy_adapter/examples/demo_client.py +341 -0
  93. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  94. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  95. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  96. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  97. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  98. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  99. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  100. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  101. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  102. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  103. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  104. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  105. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  106. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  107. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  108. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  109. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  110. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  111. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  112. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  124. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  125. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  126. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  127. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  128. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  129. mcp_proxy_adapter/examples/roles.json +38 -0
  130. mcp_proxy_adapter/examples/run_example.py +81 -0
  131. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  132. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  133. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  134. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  135. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  136. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  137. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  138. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  139. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  140. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  141. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  142. mcp_proxy_adapter/examples/test_config_generator.py +110 -0
  143. mcp_proxy_adapter/examples/test_examples.py +344 -0
  144. mcp_proxy_adapter/examples/universal_client.py +628 -0
  145. mcp_proxy_adapter/main.py +21 -10
  146. mcp_proxy_adapter/utils/config_generator.py +727 -0
  147. mcp_proxy_adapter/version.py +5 -2
  148. mcp_proxy_adapter-6.1.1.dist-info/METADATA +205 -0
  149. mcp_proxy_adapter-6.1.1.dist-info/RECORD +197 -0
  150. mcp_proxy_adapter-6.1.1.dist-info/entry_points.txt +2 -0
  151. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/licenses/LICENSE +2 -2
  152. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  153. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  154. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  155. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  156. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  157. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  158. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  159. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  160. mcp_proxy_adapter/api/middleware/security.py +0 -376
  161. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  162. mcp_proxy_adapter/examples/__init__.py +0 -7
  163. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  164. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  165. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  166. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  167. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  168. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  169. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  170. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  171. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  172. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  173. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  174. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  175. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  176. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  177. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  178. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  179. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  180. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  181. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  182. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  183. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  184. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  185. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  186. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  187. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  188. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  189. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  190. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  191. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  192. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  193. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  194. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  195. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  196. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  197. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  198. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  199. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  200. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  201. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  202. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  203. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  204. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  205. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  206. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  207. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  208. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  209. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  210. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  211. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  212. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  213. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  214. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  215. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  216. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  217. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  218. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  219. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  220. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  221. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  222. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  223. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  224. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  225. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  226. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  227. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  228. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  229. mcp_proxy_adapter/tests/__init__.py +0 -0
  230. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  231. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  232. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  233. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  234. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  235. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  236. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  237. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  238. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  239. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  240. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  241. mcp_proxy_adapter/tests/conftest.py +0 -131
  242. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  243. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  244. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  245. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  246. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  247. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  248. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  249. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  250. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  251. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  252. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  253. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  254. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  255. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  256. mcp_proxy_adapter/tests/test_config.py +0 -127
  257. mcp_proxy_adapter/tests/test_utils.py +0 -65
  258. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  259. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  260. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  261. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  262. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  263. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/WHEEL +0 -0
  264. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/top_level.txt +0 -0
@@ -1,531 +0,0 @@
1
- """
2
- Tests for tool_integration module.
3
-
4
- This module contains comprehensive tests for the ToolIntegration class
5
- and related functions to ensure 90%+ code coverage.
6
- """
7
-
8
- import pytest
9
- import json
10
- from unittest.mock import Mock, patch, MagicMock
11
- from typing import Dict, Any
12
-
13
- from mcp_proxy_adapter.api.tool_integration import ToolIntegration, generate_tool_help
14
- from mcp_proxy_adapter.commands.command_registry import CommandRegistry
15
-
16
-
17
- class TestToolIntegration:
18
- """Test cases for ToolIntegration class."""
19
-
20
- @pytest.fixture
21
- def mock_registry(self):
22
- """Create a mock command registry for testing."""
23
- registry = Mock(spec=CommandRegistry)
24
-
25
- # Mock metadata for commands
26
- registry.get_all_metadata.return_value = {
27
- "test_command": {
28
- "summary": "Test command description",
29
- "params": {
30
- "param1": {
31
- "type": "строка",
32
- "description": "Test parameter",
33
- "required": True
34
- },
35
- "param2": {
36
- "type": "целое число",
37
- "description": "Another parameter",
38
- "required": False
39
- }
40
- },
41
- "examples": [
42
- {
43
- "command": "test_command",
44
- "params": {"param1": "value1"}
45
- }
46
- ]
47
- },
48
- "another_command": {
49
- "summary": "Another test command",
50
- "params": {
51
- "param3": {
52
- "type": "логическое значение",
53
- "description": "Boolean parameter",
54
- "required": True
55
- }
56
- },
57
- "examples": [
58
- {
59
- "command": "another_command",
60
- "params": {"param3": True}
61
- }
62
- ]
63
- }
64
- }
65
-
66
- return registry
67
-
68
- @pytest.fixture
69
- def mock_api_tool_description(self):
70
- """Mock APIToolDescription class."""
71
- with patch('mcp_proxy_adapter.api.tool_integration.APIToolDescription') as mock:
72
- mock.generate_tool_description.return_value = {
73
- "description": "Test tool description",
74
- "supported_commands": {
75
- "test_command": {
76
- "params": {
77
- "param1": {
78
- "type": "строка",
79
- "description": "Test parameter"
80
- }
81
- }
82
- }
83
- }
84
- }
85
- mock.generate_tool_description_text.return_value = "# Test Tool\n\nTest description"
86
- yield mock
87
-
88
- def test_generate_tool_schema_success(self, mock_registry, mock_api_tool_description):
89
- """Test successful tool schema generation."""
90
- tool_name = "test_tool"
91
- description = "Custom tool description"
92
-
93
- schema = ToolIntegration.generate_tool_schema(tool_name, mock_registry, description)
94
-
95
- # Verify schema structure
96
- assert schema["name"] == tool_name
97
- assert schema["description"] == description
98
- assert "parameters" in schema
99
- assert "properties" in schema["parameters"]
100
- assert "command" in schema["parameters"]["properties"]
101
- assert "params" in schema["parameters"]["properties"]
102
-
103
- # Verify command enum
104
- command_enum = schema["parameters"]["properties"]["command"]["enum"]
105
- assert "test_command" in command_enum
106
-
107
- # Verify parameter types
108
- param_types = schema["parameters"]["properties"]["params"]["properties"]
109
- assert "param1" in param_types
110
- assert param_types["param1"]["type"] == "string"
111
-
112
- def test_generate_tool_schema_without_description(self, mock_registry, mock_api_tool_description):
113
- """Test tool schema generation without custom description."""
114
- tool_name = "test_tool"
115
-
116
- schema = ToolIntegration.generate_tool_schema(tool_name, mock_registry)
117
-
118
- assert schema["description"] == "Test tool description"
119
-
120
- def test_generate_tool_schema_parameter_type_conversion(self, mock_registry):
121
- """Test parameter type conversion from Russian to JSON Schema types."""
122
- with patch('mcp_proxy_adapter.api.tool_integration.APIToolDescription') as mock:
123
- mock.generate_tool_description.return_value = {
124
- "description": "Test tool",
125
- "supported_commands": {
126
- "test_command": {
127
- "params": {
128
- "string_param": {"type": "строка", "description": "String"},
129
- "int_param": {"type": "целое число", "description": "Integer"},
130
- "float_param": {"type": "число", "description": "Float"},
131
- "bool_param": {"type": "логическое значение", "description": "Boolean"},
132
- "array_param": {"type": "список", "description": "Array"},
133
- "object_param": {"type": "объект", "description": "Object"},
134
- "unknown_param": {"type": "неизвестный", "description": "Unknown"}
135
- }
136
- }
137
- }
138
- }
139
-
140
- schema = ToolIntegration.generate_tool_schema("test_tool", mock_registry)
141
- param_types = schema["parameters"]["properties"]["params"]["properties"]
142
-
143
- assert param_types["string_param"]["type"] == "string"
144
- assert param_types["int_param"]["type"] == "integer"
145
- assert param_types["float_param"]["type"] == "number"
146
- assert param_types["bool_param"]["type"] == "boolean"
147
- assert param_types["array_param"]["type"] == "array"
148
- assert param_types["object_param"]["type"] == "object"
149
- assert param_types["unknown_param"]["type"] == "string" # Default fallback
150
-
151
- def test_generate_tool_documentation_markdown(self, mock_registry, mock_api_tool_description):
152
- """Test markdown documentation generation."""
153
- tool_name = "test_tool"
154
-
155
- doc = ToolIntegration.generate_tool_documentation(tool_name, mock_registry, "markdown")
156
-
157
- assert doc == "# Test Tool\n\nTest description"
158
- mock_api_tool_description.generate_tool_description_text.assert_called_once_with(tool_name, mock_registry)
159
-
160
- def test_generate_tool_documentation_html(self, mock_registry, mock_api_tool_description):
161
- """Test HTML documentation generation."""
162
- tool_name = "test_tool"
163
-
164
- doc = ToolIntegration.generate_tool_documentation(tool_name, mock_registry, "html")
165
-
166
- assert "<html>" in doc
167
- assert "<body>" in doc
168
- assert "Test Tool" in doc
169
-
170
- def test_generate_tool_documentation_default_format(self, mock_registry, mock_api_tool_description):
171
- """Test documentation generation with default format."""
172
- tool_name = "test_tool"
173
-
174
- doc = ToolIntegration.generate_tool_documentation(tool_name, mock_registry, "unknown")
175
-
176
- assert doc == "# Test Tool\n\nTest description"
177
-
178
- def test_register_external_tools_success(self, mock_registry, mock_api_tool_description):
179
- """Test successful external tool registration."""
180
- tool_names = ["tool1", "tool2"]
181
-
182
- results = ToolIntegration.register_external_tools(mock_registry, tool_names)
183
-
184
- assert len(results) == 2
185
- assert results["tool1"]["status"] == "success"
186
- assert results["tool2"]["status"] == "success"
187
- assert "schema" in results["tool1"]
188
- assert "schema" in results["tool2"]
189
-
190
- def test_register_external_tools_with_error(self, mock_registry):
191
- """Test external tool registration with error."""
192
- with patch('mcp_proxy_adapter.api.tool_integration.APIToolDescription') as mock:
193
- mock.generate_tool_description.side_effect = Exception("Test error")
194
-
195
- tool_names = ["error_tool"]
196
- results = ToolIntegration.register_external_tools(mock_registry, tool_names)
197
-
198
- assert results["error_tool"]["status"] == "error"
199
- assert "Test error" in results["error_tool"]["error"]
200
-
201
- def test_register_external_tools_empty_list(self, mock_registry):
202
- """Test external tool registration with empty list."""
203
- results = ToolIntegration.register_external_tools(mock_registry, [])
204
-
205
- assert results == {}
206
-
207
- def test_extract_parameter_types(self):
208
- """Test parameter type extraction."""
209
- commands = {
210
- "cmd1": {
211
- "params": {
212
- "param1": {"type": "строка", "description": "String param"},
213
- "param2": {"type": "целое число", "description": "Integer param"}
214
- }
215
- },
216
- "cmd2": {
217
- "params": {
218
- "param3": {"type": "логическое значение", "description": "Boolean param"}
219
- }
220
- }
221
- }
222
-
223
- parameter_types = ToolIntegration._extract_parameter_types(commands)
224
-
225
- assert parameter_types["param1"]["type"] == "string"
226
- assert parameter_types["param2"]["type"] == "integer"
227
- assert parameter_types["param3"]["type"] == "boolean"
228
- assert parameter_types["param1"]["description"] == "String param"
229
-
230
- def test_extract_parameter_types_empty_commands(self):
231
- """Test parameter type extraction with empty commands."""
232
- parameter_types = ToolIntegration._extract_parameter_types({})
233
-
234
- assert parameter_types == {}
235
-
236
- def test_extract_parameter_types_commands_without_params(self):
237
- """Test parameter type extraction for commands without parameters."""
238
- commands = {
239
- "cmd1": {"params": {}},
240
- "cmd2": {"params": None}
241
- }
242
-
243
- parameter_types = ToolIntegration._extract_parameter_types(commands)
244
-
245
- assert parameter_types == {}
246
-
247
- def test_extract_parameter_types_missing_type(self):
248
- """Test parameter type extraction with missing type information."""
249
- commands = {
250
- "cmd1": {
251
- "params": {
252
- "param1": {"description": "Param without type"}
253
- }
254
- }
255
- }
256
-
257
- parameter_types = ToolIntegration._extract_parameter_types(commands)
258
-
259
- assert parameter_types["param1"]["type"] == "string" # Default fallback
260
-
261
-
262
- class TestGenerateToolHelp:
263
- """Test cases for generate_tool_help function."""
264
-
265
- @pytest.fixture
266
- def mock_registry(self):
267
- """Create a mock command registry for testing."""
268
- registry = Mock(spec=CommandRegistry)
269
-
270
- registry.get_all_metadata.return_value = {
271
- "help": {
272
- "summary": "Show help information",
273
- "params": {
274
- "command": {
275
- "type": "строка",
276
- "description": "Command name",
277
- "required": False
278
- }
279
- },
280
- "examples": [
281
- {
282
- "command": "help",
283
- "params": {"command": "test"}
284
- }
285
- ]
286
- },
287
- "config": {
288
- "summary": "Get configuration",
289
- "params": {
290
- "section": {
291
- "type": "строка",
292
- "description": "Configuration section",
293
- "required": True
294
- }
295
- },
296
- "examples": [
297
- {
298
- "command": "config",
299
- "params": {"section": "database"}
300
- }
301
- ]
302
- }
303
- }
304
-
305
- return registry
306
-
307
- def test_generate_tool_help_success(self, mock_registry):
308
- """Test successful tool help generation."""
309
- tool_name = "test_tool"
310
-
311
- help_text = generate_tool_help(tool_name, mock_registry)
312
-
313
- # Verify basic structure
314
- assert f"# Инструмент {tool_name}" in help_text
315
- assert "Позволяет выполнять команды через JSON-RPC протокол" in help_text
316
- assert "## Доступные команды:" in help_text
317
-
318
- # Verify command information
319
- assert "### help" in help_text
320
- assert "Show help information" in help_text
321
- assert "### config" in help_text
322
- assert "Get configuration" in help_text
323
-
324
- # Verify parameter information
325
- assert "Параметры:" in help_text
326
- assert "command: опциональный" in help_text
327
- assert "section: обязательный" in help_text
328
-
329
- # Verify JSON examples
330
- assert "```json" in help_text
331
- assert '"command": "help"' in help_text
332
- assert '"command": "test"' in help_text
333
-
334
- def test_generate_tool_help_without_params(self, mock_registry):
335
- """Test tool help generation for commands without parameters."""
336
- mock_registry.get_all_metadata.return_value = {
337
- "simple_command": {
338
- "summary": "Simple command without params",
339
- "params": {},
340
- "examples": [
341
- {
342
- "command": "simple_command",
343
- "params": {}
344
- }
345
- ]
346
- }
347
- }
348
-
349
- help_text = generate_tool_help("test_tool", mock_registry)
350
-
351
- assert "### simple_command" in help_text
352
- assert "Simple command without params" in help_text
353
- # Should not contain "Параметры:" section for commands without params
354
-
355
- def test_generate_tool_help_without_examples(self, mock_registry):
356
- """Test tool help generation for commands without examples."""
357
- mock_registry.get_all_metadata.return_value = {
358
- "no_example_command": {
359
- "summary": "Command without examples",
360
- "params": {
361
- "param1": {
362
- "type": "строка",
363
- "description": "Test parameter",
364
- "required": True
365
- }
366
- },
367
- "examples": []
368
- }
369
- }
370
-
371
- help_text = generate_tool_help("test_tool", mock_registry)
372
-
373
- assert "### no_example_command" in help_text
374
- assert "Command without examples" in help_text
375
- # Should not contain JSON example section
376
-
377
- def test_generate_tool_help_empty_registry(self, mock_registry):
378
- """Test tool help generation with empty command registry."""
379
- mock_registry.get_all_metadata.return_value = {}
380
-
381
- help_text = generate_tool_help("test_tool", mock_registry)
382
-
383
- assert "## Доступные команды:" in help_text
384
- # Should not contain any command sections
385
-
386
- def test_generate_tool_help_with_none_params(self, mock_registry):
387
- """Test tool help generation with None params."""
388
- mock_registry.get_all_metadata.return_value = {
389
- "command": {
390
- "summary": "Test command",
391
- "params": None,
392
- "examples": []
393
- }
394
- }
395
-
396
- help_text = generate_tool_help("test_tool", mock_registry)
397
-
398
- assert "### command" in help_text
399
- # Should handle None params gracefully
400
-
401
- def test_generate_tool_help_with_missing_examples(self, mock_registry):
402
- """Test tool help generation with missing examples key."""
403
- mock_registry.get_all_metadata.return_value = {
404
- "command": {
405
- "summary": "Test command",
406
- "params": {}
407
- }
408
- }
409
-
410
- help_text = generate_tool_help("test_tool", mock_registry)
411
-
412
- assert "### command" in help_text
413
- # Should handle missing examples key gracefully
414
-
415
-
416
- class TestToolIntegrationEdgeCases:
417
- """Test edge cases and error conditions."""
418
-
419
- def test_generate_tool_schema_with_none_registry(self):
420
- """Test tool schema generation with None registry."""
421
- with pytest.raises(AttributeError):
422
- ToolIntegration.generate_tool_schema("test_tool", None)
423
-
424
- def test_generate_tool_documentation_with_none_registry(self):
425
- """Test documentation generation with None registry."""
426
- with pytest.raises(AttributeError):
427
- ToolIntegration.generate_tool_documentation("test_tool", None)
428
-
429
- def test_register_external_tools_with_none_registry(self):
430
- """Test external tool registration with None registry."""
431
- # This should handle None gracefully and return error status
432
- results = ToolIntegration.register_external_tools(None, ["tool1"])
433
- assert "tool1" in results
434
- assert results["tool1"]["status"] == "error"
435
- assert "get_all_metadata" in results["tool1"]["error"]
436
-
437
- def test_generate_tool_help_with_none_registry(self):
438
- """Test tool help generation with None registry."""
439
- with pytest.raises(AttributeError):
440
- generate_tool_help("test_tool", None)
441
-
442
- @patch('mcp_proxy_adapter.api.tool_integration.logger')
443
- def test_register_external_tools_logging(self, mock_logger):
444
- """Test that logging is called during tool registration."""
445
- mock_registry = Mock(spec=CommandRegistry)
446
- with patch('mcp_proxy_adapter.api.tool_integration.APIToolDescription') as mock:
447
- mock.generate_tool_description.return_value = {
448
- "description": "Test tool",
449
- "supported_commands": {}
450
- }
451
-
452
- ToolIntegration.register_external_tools(mock_registry, ["test_tool"])
453
-
454
- # Verify info log for successful registration
455
- mock_logger.info.assert_called_with("Successfully registered tool: test_tool")
456
-
457
- @patch('mcp_proxy_adapter.api.tool_integration.logger')
458
- def test_register_external_tools_error_logging(self, mock_logger):
459
- """Test that error logging is called during failed tool registration."""
460
- mock_registry = Mock(spec=CommandRegistry)
461
- with patch('mcp_proxy_adapter.api.tool_integration.APIToolDescription') as mock:
462
- mock.generate_tool_description.side_effect = Exception("Test error")
463
-
464
- ToolIntegration.register_external_tools(mock_registry, ["error_tool"])
465
-
466
- # Verify debug log for error
467
- mock_logger.debug.assert_called_with("Error registering tool error_tool: Test error")
468
-
469
-
470
- class TestToolIntegrationIntegration:
471
- """Integration tests for ToolIntegration class."""
472
-
473
- @pytest.fixture
474
- def real_registry(self):
475
- """Create a real command registry for integration testing."""
476
- from mcp_proxy_adapter.commands.command_registry import CommandRegistry
477
- from mcp_proxy_adapter.commands.base import Command
478
-
479
- registry = CommandRegistry()
480
-
481
- # Create a proper mock that inherits from Command
482
- class MockCommand(Command):
483
- name = "integration_test"
484
-
485
- @classmethod
486
- def get_metadata(cls):
487
- return {
488
- "summary": "Integration test command",
489
- "description": "Integration test command description",
490
- "params": {
491
- "test_param": {
492
- "type": "строка",
493
- "description": "Test parameter",
494
- "required": True
495
- }
496
- },
497
- "examples": [
498
- {
499
- "command": "integration_test",
500
- "params": {"test_param": "value"}
501
- }
502
- ]
503
- }
504
-
505
- async def execute(self, **kwargs):
506
- return {"result": "test"}
507
-
508
- registry.register(MockCommand())
509
-
510
- return registry
511
-
512
- def test_integration_generate_tool_schema(self, real_registry):
513
- """Integration test for tool schema generation with real registry."""
514
- schema = ToolIntegration.generate_tool_schema("integration_tool", real_registry)
515
-
516
- assert schema["name"] == "integration_tool"
517
- assert "parameters" in schema
518
- assert "properties" in schema["parameters"]
519
-
520
- def test_integration_generate_tool_documentation(self, real_registry):
521
- """Integration test for tool documentation generation with real registry."""
522
- doc = ToolIntegration.generate_tool_documentation("integration_tool", real_registry)
523
-
524
- assert "integration_tool" in doc.lower()
525
-
526
- def test_integration_generate_tool_help(self, real_registry):
527
- """Integration test for tool help generation with real registry."""
528
- help_text = generate_tool_help("integration_tool", real_registry)
529
-
530
- assert "Инструмент integration_tool" in help_text
531
- assert "integration_test" in help_text
@@ -1,3 +0,0 @@
1
- """
2
- Tests for commands package.
3
- """