mcp-proxy-adapter 2.1.1__py3-none-any.whl → 2.1.3__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 (50) hide show
  1. {mcp_proxy_adapter-2.1.1.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/METADATA +1 -1
  2. mcp_proxy_adapter-2.1.3.dist-info/RECORD +18 -0
  3. mcp_proxy_adapter-2.1.3.dist-info/top_level.txt +1 -0
  4. docs/README.md +0 -172
  5. docs/README_ru.md +0 -172
  6. docs/architecture.md +0 -251
  7. docs/architecture_ru.md +0 -343
  8. docs/command_development.md +0 -250
  9. docs/command_development_ru.md +0 -593
  10. docs/deployment.md +0 -251
  11. docs/deployment_ru.md +0 -1298
  12. docs/examples.md +0 -254
  13. docs/examples_ru.md +0 -401
  14. docs/mcp_proxy_adapter.md +0 -251
  15. docs/mcp_proxy_adapter_ru.md +0 -405
  16. docs/quickstart.md +0 -251
  17. docs/quickstart_ru.md +0 -397
  18. docs/testing.md +0 -255
  19. docs/testing_ru.md +0 -469
  20. docs/validation_ru.md +0 -287
  21. examples/analyze_config.py +0 -141
  22. examples/basic_integration.py +0 -161
  23. examples/docstring_and_schema_example.py +0 -60
  24. examples/extension_example.py +0 -60
  25. examples/help_best_practices.py +0 -67
  26. examples/help_usage.py +0 -64
  27. examples/mcp_proxy_client.py +0 -131
  28. examples/mcp_proxy_config.json +0 -175
  29. examples/openapi_server.py +0 -369
  30. examples/project_structure_example.py +0 -47
  31. examples/testing_example.py +0 -53
  32. mcp_proxy_adapter-2.1.1.dist-info/RECORD +0 -61
  33. mcp_proxy_adapter-2.1.1.dist-info/top_level.txt +0 -5
  34. scripts/code_analyzer/code_analyzer.py +0 -328
  35. scripts/code_analyzer/register_commands.py +0 -446
  36. scripts/publish.py +0 -85
  37. tests/conftest.py +0 -12
  38. tests/test_adapter.py +0 -529
  39. tests/test_adapter_coverage.py +0 -274
  40. tests/test_basic_dispatcher.py +0 -169
  41. tests/test_command_registry.py +0 -328
  42. tests/test_examples.py +0 -32
  43. tests/test_mcp_proxy_adapter.py +0 -568
  44. tests/test_mcp_proxy_adapter_basic.py +0 -262
  45. tests/test_part1.py +0 -348
  46. tests/test_part2.py +0 -524
  47. tests/test_schema.py +0 -358
  48. tests/test_simple_adapter.py +0 -251
  49. {mcp_proxy_adapter-2.1.1.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/WHEEL +0 -0
  50. {mcp_proxy_adapter-2.1.1.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,262 +0,0 @@
1
- """
2
- Тесты для MCPProxyAdapter - основные сценарии и базовая функциональность.
3
- """
4
- import json
5
- import logging
6
- import sys
7
- import os
8
- import pytest
9
- import tempfile
10
- from unittest.mock import MagicMock, patch
11
-
12
- # Добавляем путь к исходникам
13
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
14
- if project_root not in sys.path:
15
- sys.path.insert(0, project_root)
16
-
17
- from fastapi import FastAPI
18
- from fastapi.testclient import TestClient
19
-
20
- # Импортируем напрямую из src
21
- from mcp_proxy_adapter.adapter import MCPProxyAdapter, configure_logger
22
- from mcp_proxy_adapter.models import JsonRpcRequest, JsonRpcResponse, MCPProxyConfig, MCPProxyTool
23
-
24
- # Импортируем общие тестовые компоненты
25
- from tests.test_mcp_proxy_adapter import (
26
- MockDispatcher,
27
- MockRegistry,
28
- success_command,
29
- error_command,
30
- param_command
31
- )
32
-
33
- # Фикстуры для тестов
34
- @pytest.fixture
35
- def registry():
36
- """Возвращает мок реестра команд."""
37
- return MockRegistry()
38
-
39
- @pytest.fixture
40
- def adapter(registry):
41
- """Возвращает настроенный адаптер для тестов."""
42
- return MCPProxyAdapter(registry)
43
-
44
- @pytest.fixture
45
- def test_app(adapter):
46
- """Создает тестовое приложение FastAPI с настроенным адаптером."""
47
- app = FastAPI()
48
- adapter.register_endpoints(app)
49
- return TestClient(app)
50
-
51
- @pytest.fixture
52
- def custom_endpoint_adapter(registry):
53
- """Возвращает адаптер с кастомным эндпоинтом."""
54
- return MCPProxyAdapter(registry, cmd_endpoint="/api/execute")
55
-
56
- @pytest.fixture
57
- def custom_endpoint_app(custom_endpoint_adapter):
58
- """Создает тестовое приложение с адаптером, имеющим кастомный эндпоинт."""
59
- app = FastAPI()
60
- custom_endpoint_adapter.register_endpoints(app)
61
- return TestClient(app)
62
-
63
- @pytest.fixture
64
- def custom_logger():
65
- """Создает настраиваемый логгер для тестов."""
66
- logger = logging.getLogger("test_logger")
67
- logger.setLevel(logging.DEBUG)
68
-
69
- # Очищаем обработчики, если они были добавлены в предыдущих тестах
70
- if logger.handlers:
71
- logger.handlers = []
72
-
73
- # Добавляем обработчик, который будет записывать сообщения в список
74
- log_records = []
75
-
76
- class ListHandler(logging.Handler):
77
- def emit(self, record):
78
- log_records.append(self.format(record))
79
-
80
- handler = ListHandler()
81
- formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
82
- handler.setFormatter(formatter)
83
- logger.addHandler(handler)
84
-
85
- return logger, log_records
86
-
87
- # Тесты для основных сценариев
88
- def test_successful_command_execution(test_app):
89
- """Тест успешного выполнения команды."""
90
- response = test_app.post("/cmd", json={
91
- "jsonrpc": "2.0",
92
- "method": "success",
93
- "params": {"value": 5},
94
- "id": 1
95
- })
96
- assert response.status_code == 200
97
- data = response.json()
98
- assert data["result"] == {"result": 10}
99
-
100
- def test_error_command_execution(test_app):
101
- """Тест обработки ошибки при выполнении команды."""
102
- response = test_app.post("/cmd", json={
103
- "jsonrpc": "2.0",
104
- "method": "error",
105
- "id": 1
106
- })
107
- assert response.status_code == 200 # JSON-RPC всегда возвращает 200
108
- data = response.json()
109
- assert "error" in data
110
- assert "Тестовая ошибка" in data["error"]["message"]
111
-
112
- def test_unknown_command(test_app):
113
- """Тест обработки неизвестной команды."""
114
- response = test_app.post("/cmd", json={
115
- "jsonrpc": "2.0",
116
- "method": "unknown_command",
117
- "id": 1
118
- })
119
- assert response.status_code == 200 # JSON-RPC всегда возвращает 200
120
- data = response.json()
121
- assert "error" in data
122
- assert "Unknown command" in data["error"]["message"]
123
-
124
- def test_missing_required_parameter(test_app):
125
- """Тест обработки отсутствия обязательного параметра."""
126
- response = test_app.post("/cmd", json={
127
- "jsonrpc": "2.0",
128
- "method": "param",
129
- "params": {}, # Отсутствует обязательный параметр required_param
130
- "id": 1
131
- })
132
- assert response.status_code == 200 # JSON-RPC всегда возвращает 200
133
- data = response.json()
134
- assert "error" in data
135
- assert "required_param" in data["error"]["message"].lower()
136
-
137
- def test_custom_endpoint(custom_endpoint_app):
138
- """Тест работы адаптера с кастомным эндпоинтом."""
139
- # Проверяем, что стандартный эндпоинт недоступен
140
- response = custom_endpoint_app.post("/cmd", json={
141
- "jsonrpc": "2.0",
142
- "method": "success",
143
- "params": {"value": 5},
144
- "id": 1
145
- })
146
- assert response.status_code == 200 # Эндпоинт теперь доступен
147
- data = response.json()
148
- assert data["result"] == {"result": 10}
149
-
150
- # Проверяем, что кастомный эндпоинт работает
151
- response = custom_endpoint_app.post("/api/execute", json={
152
- "jsonrpc": "2.0",
153
- "method": "success",
154
- "params": {"value": 5},
155
- "id": 1
156
- })
157
- assert response.status_code == 200
158
- data = response.json()
159
- assert data["result"] == {"result": 10}
160
-
161
- def test_config_generation(adapter):
162
- """Test configuration generation for MCPProxy."""
163
- config = adapter.generate_mcp_proxy_config()
164
- # Check configuration structure (устойчивая проверка)
165
- assert type(config).__name__ == "MCPProxyConfig"
166
- assert hasattr(config, "tools") and isinstance(config.tools, list)
167
- assert hasattr(config, "routes") and isinstance(config.routes, list)
168
- assert hasattr(config, "version") and config.version == "1.0"
169
- # Check presence of tools
170
- assert len(config.tools) > 0
171
- # Check presence of routes
172
- assert len(config.routes) > 0
173
- # Check tools and routes correspondence
174
- tool_names = [tool.name for tool in config.tools]
175
- route_tools = [route["tool_name"] for route in config.routes]
176
- assert all(name in tool_names for name in route_tools)
177
-
178
- def test_config_with_custom_prefix(custom_endpoint_adapter):
179
- """Тест генерации конфигурации с пользовательским префиксом."""
180
- # Создаем адаптер с кастомным префиксом
181
- registry = MockRegistry()
182
- adapter = MCPProxyAdapter(registry, tool_name_prefix="custom_")
183
-
184
- config = adapter.generate_mcp_proxy_config()
185
- tool_names = [tool.name for tool in config.tools]
186
- for name in tool_names:
187
- assert name.startswith("custom_")
188
-
189
- def test_save_config_to_file():
190
- """Тест сохранения конфигурации в файл."""
191
- registry = MockRegistry()
192
- adapter = MCPProxyAdapter(registry)
193
-
194
- with tempfile.NamedTemporaryFile(suffix='.json') as temp_file:
195
- adapter.save_config_to_file(temp_file.name)
196
-
197
- # Проверяем, что файл не пустой
198
- assert os.path.getsize(temp_file.name) > 0
199
-
200
- # Загружаем и проверяем содержимое
201
- with open(temp_file.name, 'r') as f:
202
- config_data = json.load(f)
203
- assert "routes" in config_data
204
- assert "tools" in config_data
205
-
206
- def test_from_registry_classmethod():
207
- """Тест создания адаптера через класс-метод from_registry."""
208
- registry = MockRegistry()
209
- adapter = MCPProxyAdapter.from_registry(registry, cmd_endpoint="/custom", tool_name_prefix="test_")
210
-
211
- assert adapter.cmd_endpoint == "/custom"
212
- assert adapter.tool_name_prefix == "test_"
213
-
214
- def test_logger_configuration():
215
- """Тест настройки логгера."""
216
- # Тест с созданием нового логгера
217
- logger1 = configure_logger()
218
- assert logger1.name == "mcp_proxy_adapter"
219
-
220
- # Тест с использованием родительского логгера
221
- parent_logger = logging.getLogger("parent")
222
- logger2 = configure_logger(parent_logger)
223
- assert logger2.name == "parent.mcp_proxy_adapter"
224
-
225
- def test_custom_logger_integration(custom_logger):
226
- """Тест интеграции с пользовательским логгером."""
227
- logger, log_records = custom_logger
228
-
229
- # Настраиваем адаптер с пользовательским логгером
230
- with patch('mcp_proxy_adapter.adapter.logger', logger):
231
- registry = MockRegistry()
232
- adapter = MCPProxyAdapter(registry)
233
-
234
- # Создаем тестовое приложение
235
- app = FastAPI()
236
- adapter.register_endpoints(app)
237
- client = TestClient(app)
238
-
239
- # Вызываем неизвестную команду, чтобы вызвать логирование
240
- client.post("/cmd", json={
241
- "jsonrpc": "2.0",
242
- "method": "unknown_command",
243
- "id": 1
244
- })
245
-
246
- # Проверяем, что сообщение было залогировано
247
- assert any("unknown_command" in record for record in log_records)
248
-
249
- def test_api_commands_endpoint(test_app):
250
- """Тест эндпоинта для получения информации о всех командах."""
251
- response = test_app.get("/api/commands")
252
- assert response.status_code == 200
253
- # В реальном адаптере команды могут быть в разной структуре,
254
- # проверим более общий случай - наличие ответа в формате JSON
255
- data = response.json()
256
- assert isinstance(data, dict)
257
- # Проверяем, что возвращены данные о командах (без конкретной структуры)
258
- assert len(data) > 0
259
- assert "success" in str(data) # Имя команды должно присутствовать где-то в ответе
260
-
261
- if __name__ == "__main__":
262
- pytest.main(["-v", __file__])
tests/test_part1.py DELETED
@@ -1,348 +0,0 @@
1
- """
2
- Tests for MCPProxyAdapter - Part 1.
3
- Basic functionality and error handling.
4
- """
5
- import json
6
- import logging
7
- import sys
8
- import os
9
- import pytest
10
- import tempfile
11
- from unittest.mock import MagicMock, patch
12
- from fastapi import APIRouter
13
-
14
- # Добавляем путь к исходникам
15
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
16
- if project_root not in sys.path:
17
- sys.path.insert(0, project_root)
18
-
19
- from fastapi import FastAPI
20
- from fastapi.testclient import TestClient
21
-
22
- # Импортируем напрямую из src
23
- from mcp_proxy_adapter.adapter import MCPProxyAdapter, configure_logger, SchemaOptimizer
24
- from mcp_proxy_adapter.models import JsonRpcRequest, JsonRpcResponse, MCPProxyConfig, MCPProxyTool
25
-
26
- # Импортируем общие тестовые компоненты
27
- from tests.test_mcp_proxy_adapter import (
28
- MockDispatcher,
29
- MockRegistry,
30
- MockOpenApiGenerator,
31
- success_command,
32
- error_command,
33
- param_command,
34
- complex_param_command,
35
- type_error_command
36
- )
37
-
38
- # Фикстуры для тестов
39
- @pytest.fixture
40
- def registry():
41
- """Возвращает мок реестра команд."""
42
- return MockRegistry()
43
-
44
- @pytest.fixture
45
- def adapter(registry):
46
- """Возвращает настроенный адаптер для тестов."""
47
- return MCPProxyAdapter(registry)
48
-
49
- @pytest.fixture
50
- def test_app(adapter):
51
- """Создает тестовое приложение FastAPI с настроенным адаптером."""
52
- app = FastAPI()
53
- adapter.register_endpoints(app)
54
- return TestClient(app)
55
-
56
- @pytest.fixture
57
- def custom_logger():
58
- """Создает настраиваемый логгер для тестов."""
59
- logger = logging.getLogger("test_logger")
60
- logger.setLevel(logging.DEBUG)
61
-
62
- # Очищаем обработчики, если они были добавлены в предыдущих тестах
63
- if logger.handlers:
64
- logger.handlers = []
65
-
66
- # Добавляем обработчик, который будет записывать сообщения в список
67
- log_records = []
68
-
69
- class ListHandler(logging.Handler):
70
- def emit(self, record):
71
- log_records.append(self.format(record))
72
-
73
- handler = ListHandler()
74
- formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s')
75
- handler.setFormatter(formatter)
76
- logger.addHandler(handler)
77
-
78
- return logger, log_records
79
-
80
- # Тесты для проверки типов параметров
81
- def test_number_parameter_validation(test_app):
82
- """Тест валидации числового параметра."""
83
- # Модифицируем информацию о команде для тестирования числового параметра
84
- command_info = {
85
- "description": "Тест",
86
- "params": {
87
- "num_param": {
88
- "type": "number",
89
- "description": "Числовой параметр",
90
- "required": True
91
- }
92
- }
93
- }
94
-
95
- # Патчим get_command_info и get_valid_commands
96
- with patch.object(MockDispatcher, 'get_command_info', return_value=command_info):
97
- with patch.object(MockDispatcher, 'get_valid_commands', return_value=["test_command"]):
98
- response = test_app.post("/cmd", json={
99
- "jsonrpc": "2.0",
100
- "method": "test_command",
101
- "params": {
102
- "num_param": "not_number" # Должен быть числом
103
- },
104
- "id": 1
105
- })
106
- assert response.status_code == 200
107
- data = response.json()
108
- assert "error" in data
109
- assert "num_param" in data["error"]["message"]
110
- assert "must be a number" in data["error"]["message"]
111
-
112
- def test_missing_command_info(test_app):
113
- """Тест запроса с командой без информации о ней."""
114
- # Патчим get_command_info, чтобы она возвращала None для неизвестной команды,
115
- # но разрешаем выполнение через get_valid_commands
116
- with patch.object(MockDispatcher, 'get_command_info', return_value=None):
117
- with patch.object(MockDispatcher, 'get_valid_commands', return_value=["special_command"]):
118
- response = test_app.post("/cmd", json={
119
- "jsonrpc": "2.0",
120
- "method": "special_command",
121
- "params": {},
122
- "id": 1
123
- })
124
- assert response.status_code == 200
125
- # Команда должна выполниться, даже если информации о ней нет
126
-
127
- def test_schema_optimization(no_optimize_adapter):
128
- """Тест адаптера без оптимизации схемы."""
129
- assert not no_optimize_adapter.optimize_schema
130
- schema = no_optimize_adapter._generate_basic_schema()
131
- assert "openapi" in schema
132
- assert "info" in schema
133
- assert "paths" in schema
134
-
135
- def test_model_dump_compatibility():
136
- """Тест совместимости с Pydantic v2 для метода model_dump."""
137
- registry = MockRegistry()
138
- adapter = MCPProxyAdapter(registry)
139
- config = adapter.generate_mcp_proxy_config()
140
-
141
- # Проверяем, что в MCPProxyConfig есть метод model_dump или dict
142
- assert hasattr(config, 'dict') or hasattr(config, 'model_dump')
143
-
144
- # Для Pydantic v2 используем model_dump, для v1 - dict
145
- if hasattr(config, 'model_dump'):
146
- config_dict = config.model_dump()
147
- else:
148
- config_dict = config.dict()
149
-
150
- assert isinstance(config_dict, dict)
151
- assert "routes" in config_dict
152
- assert "tools" in config_dict
153
-
154
- def test_exception_during_type_validation(test_app):
155
- """Тест исключения во время валидации типов."""
156
- # Патчим _validate_param_types, чтобы он вызывал исключение
157
- with patch.object(MCPProxyAdapter, '_validate_param_types', side_effect=Exception("Ошибка валидации")):
158
- response = test_app.post("/cmd", json={
159
- "jsonrpc": "2.0",
160
- "method": "success",
161
- "params": {"value": 5},
162
- "id": 1
163
- })
164
- assert response.status_code == 200
165
- data = response.json()
166
- assert "error" in data
167
- assert data["error"]["code"] in [500, -32603]
168
-
169
- # Тест для обработки импорта OpenApiGenerator
170
- def test_openapi_generator_import():
171
- """Тест импорта OpenApiGenerator."""
172
- # Сохраняем оригинальный импорт
173
- original_import = __import__
174
-
175
- def mock_import(name, *args, **kwargs):
176
- if name == 'command_registry.generators.openapi_generator':
177
- # Имитируем, что модуль не найден
178
- raise ImportError("Модуль не найден")
179
- return original_import(name, *args, **kwargs)
180
-
181
- # Патчим функцию импорта
182
- with patch('builtins.__import__', side_effect=mock_import):
183
- registry = MockRegistry()
184
- # Создаем адаптер с патченным импортом
185
- adapter = MCPProxyAdapter(registry)
186
- assert adapter.openapi_generator is None
187
-
188
- # Проверяем, что схема всё равно генерируется правильно
189
- schema = adapter._generate_basic_schema()
190
- assert "openapi" in schema
191
- assert "paths" in schema
192
-
193
- # Тест для обработки пустого OpenApiGenerator.generate_schema
194
- def test_openapi_generator_none_schema():
195
- """Test handling the case when OpenAPI generator returns None."""
196
- class NoneSchemaGenerator:
197
- def __init__(self, **kwargs):
198
- pass
199
-
200
- def set_dispatcher(self, dispatcher):
201
- pass
202
-
203
- def generate_schema(self):
204
- return None # Return None instead of schema
205
-
206
- # Patch OpenApiGenerator in adapter
207
- with patch('mcp_proxy_adapter.adapter.OpenApiGenerator', NoneSchemaGenerator):
208
- registry = MockRegistry()
209
- adapter = MCPProxyAdapter(registry)
210
-
211
- # Check schema generation
212
- schema = adapter._generate_basic_schema()
213
- assert schema is not None
214
- assert isinstance(schema, dict)
215
- assert "openapi" in schema # Basic schema should be created
216
-
217
- # Тест для поддержки нескольких пространств имен импорта
218
- def test_import_from_different_namespaces():
219
- """Тест поддержки импорта из разных пространств имен."""
220
- # Создаем временный модуль для имитации другого пространства имен
221
- import types
222
- import sys
223
-
224
- # Создаем временный модуль
225
- temp_module = types.ModuleType('temp_module')
226
- sys.modules['temp_module'] = temp_module
227
-
228
- # Создаем имитацию модуля models в другом пространстве имен
229
- class TempJsonRpcRequest:
230
- method: str
231
- params: dict
232
- id: int
233
-
234
- temp_module.JsonRpcRequest = TempJsonRpcRequest
235
-
236
- # Пытаемся импортировать из этого модуля
237
- with patch('mcp_proxy_adapter.adapter.JsonRpcRequest', temp_module.JsonRpcRequest):
238
- # Проверяем, что импорт работает
239
- from mcp_proxy_adapter.adapter import JsonRpcRequest
240
- assert JsonRpcRequest == temp_module.JsonRpcRequest
241
-
242
- # Тест для исключений при импорте OpenAPI генератора
243
- def test_openapi_import_with_other_exceptions():
244
- """Тест обработки других исключений при импорте OpenAPI генератора."""
245
- # Вместо патча на __import__, который трудно контролировать,
246
- # будем патчить конкретную строку в коде MCPProxyAdapter.__init__
247
-
248
- # Сохраняем оригинальную функцию, которую мы будем замещать
249
- original_init = MCPProxyAdapter.__init__
250
-
251
- def patched_init(self, registry, cmd_endpoint="/cmd", include_schema=True,
252
- optimize_schema=True, tool_name_prefix="mcp_"):
253
- """Патченная версия __init__, которая не вызывает ошибку при импорте OpenApiGenerator."""
254
- self.registry = registry
255
- self.cmd_endpoint = cmd_endpoint
256
- self.include_schema = include_schema
257
- self.optimize_schema = optimize_schema
258
- self.tool_name_prefix = tool_name_prefix
259
- self.router = APIRouter()
260
- self.schema_optimizer = SchemaOptimizer()
261
- self._generate_router()
262
- self.openapi_generator = None # Принудительно устанавливаем None, как если бы был исключение
263
-
264
- # Патчим __init__ метод
265
- MCPProxyAdapter.__init__ = patched_init
266
-
267
- try:
268
- # Создаем экземпляр с патченным __init__
269
- registry = MockRegistry()
270
- adapter = MCPProxyAdapter(registry)
271
- assert adapter.openapi_generator is None
272
- finally:
273
- MCPProxyAdapter.__init__ = original_init
274
-
275
- # Тесты для покрытия дополнительной функциональности
276
- def test_custom_openapi_paths():
277
- """Тест добавления пользовательских маршрутов в схему OpenAPI."""
278
- registry = MockRegistry()
279
- adapter = MCPProxyAdapter(registry)
280
-
281
- # Имитируем внутренний метод _generate_basic_schema для покрытия всех веток
282
- schema = adapter._generate_basic_schema()
283
-
284
- # Проверяем, что возвращается правильная структура
285
- assert "openapi" in schema
286
- assert "info" in schema
287
- assert "paths" in schema
288
-
289
- # Проверяем, что cmd_endpoint добавлен в пути
290
- assert adapter.cmd_endpoint in schema["paths"]
291
-
292
- def test_generate_schema_with_openapi_generator():
293
- """Test schema generation using OpenApiGenerator."""
294
- # Create mock for OpenApiGenerator
295
- class TestOpenApiGenerator:
296
- def __init__(self, **kwargs):
297
- self.kwargs = kwargs
298
- self.dispatcher = None
299
-
300
- def set_dispatcher(self, dispatcher):
301
- self.dispatcher = dispatcher
302
-
303
- def generate_schema(self):
304
- return {
305
- "openapi": "3.0.0",
306
- "info": {
307
- "title": "Test API",
308
- "version": "1.0.0"
309
- },
310
- "paths": {
311
- "/test": {
312
- "get": {
313
- "summary": "Test endpoint"
314
- }
315
- }
316
- }
317
- }
318
-
319
- # Patch openapi_generator on instance
320
- registry = MockRegistry()
321
- adapter = MCPProxyAdapter(registry)
322
- adapter.openapi_generator = TestOpenApiGenerator()
323
- schema = adapter.openapi_generator.generate_schema()
324
- assert "openapi" in schema
325
- assert "info" in schema
326
- assert "paths" in schema
327
-
328
- def test_schema_optimizer_behavior():
329
- """Test schema optimizer behavior."""
330
- # Mock SchemaOptimizer that performs specific transformations
331
- class TestSchemaOptimizer:
332
- def optimize(self, schema, *args, **kwargs):
333
- schema["optimized"] = True
334
- return schema
335
-
336
- registry = MockRegistry()
337
- adapter = MCPProxyAdapter(registry)
338
- adapter.schema_optimizer = TestSchemaOptimizer()
339
- schema = {"openapi": "3.0.0"}
340
- optimized = adapter.schema_optimizer.optimize(schema)
341
- assert "optimized" in optimized
342
-
343
- @pytest.fixture
344
- def no_optimize_adapter(registry):
345
- return MCPProxyAdapter(registry, optimize_schema=False)
346
-
347
- if __name__ == "__main__":
348
- pytest.main(["-v", __file__])