mcp-proxy-adapter 2.1.2__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.2.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.2.dist-info/RECORD +0 -61
  33. mcp_proxy_adapter-2.1.2.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.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/WHEEL +0 -0
  50. {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/licenses/LICENSE +0 -0
docs/architecture_ru.md DELETED
@@ -1,343 +0,0 @@
1
- # Архитектура Command Registry
2
-
3
- Данный документ описывает архитектуру системы Command Registry, ее ключевые компоненты, их взаимодействие и принципы расширения.
4
-
5
- ## Обзор архитектуры
6
-
7
- Command Registry - это модульная система, построенная вокруг концепции централизованного хранения и управления командами. Архитектура обеспечивает гибкость, расширяемость и соблюдение принципов SOLID.
8
-
9
- Ключевые возможности системы:
10
-
11
- 1. **Определение команд как Python-функций** с использованием типизации и докстрингов
12
- 2. **Извлечение метаданных** из сигнатур функций и их документации
13
- 3. **Регистрация команд** в центральном реестре
14
- 4. **Предоставление унифицированного интерфейса** для выполнения команд
15
- 5. **Генерация документации API** на основе метаданных команд
16
- 6. **Экспорт команд** через различные протоколы (REST, JSON-RPC, CLI и т.д.)
17
-
18
- ## Компоненты системы
19
-
20
- ![Диаграмма компонентов](../diagrams/command_registry_components.png)
21
-
22
- ### Основные компоненты:
23
-
24
- 1. **Command Definition** - Определение команды (функция Python с типизацией и докстрингами)
25
- 2. **Dispatcher Component** - Диспетчер команд, отвечающий за их регистрацию и выполнение
26
- 3. **Metadata Extractor** - Извлекатель метаданных из докстрингов и сигнатур функций
27
- 4. **Protocol Adapter** - Адаптер для экспорта команд через различные протоколы
28
-
29
- ### CommandRegistry
30
-
31
- Центральный компонент системы, который:
32
-
33
- - Инициализирует и конфигурирует диспетчеры
34
- - Предоставляет интерфейс для регистрации команд
35
- - Управляет метаданными команд
36
- - Координирует взаимодействие между компонентами
37
-
38
- ## Жизненный цикл команды
39
-
40
- ### 1. Определение команды
41
-
42
- ```python
43
- def calculate_total(
44
- prices: List[float],
45
- discount: float = 0.0,
46
- tax_rate: float = 0.0
47
- ) -> float:
48
- """
49
- Рассчитывает общую стоимость с учетом скидки и налога.
50
-
51
- Args:
52
- prices: Список цен товаров
53
- discount: Скидка в процентах (0-100)
54
- tax_rate: Налоговая ставка в процентах (0-100)
55
-
56
- Returns:
57
- Общая стоимость с учетом скидки и налога
58
- """
59
- subtotal = sum(prices)
60
- discounted = subtotal * (1 - discount / 100)
61
- total = discounted * (1 + tax_rate / 100)
62
- return round(total, 2)
63
- ```
64
-
65
- ### 2. Регистрация команды
66
-
67
- ```python
68
- from command_registry import CommandRegistry
69
- from command_registry.dispatchers import CommandDispatcher
70
-
71
- # Создание реестра команд
72
- registry = CommandRegistry(CommandDispatcher())
73
-
74
- # Регистрация команды
75
- registry.register_command("calculate_total", calculate_total)
76
- ```
77
-
78
- ### 3. Выполнение команды
79
-
80
- ```python
81
- # Выполнение команды
82
- result = registry.execute(
83
- "calculate_total",
84
- {
85
- "prices": [10.0, 20.0, 30.0],
86
- "discount": 10.0,
87
- "tax_rate": 7.0
88
- }
89
- )
90
- print(result) # 57.33
91
- ```
92
-
93
- ### 4. Экспорт через API
94
-
95
- ```python
96
- from fastapi import FastAPI
97
- from command_registry.adapters import RESTAdapter
98
-
99
- app = FastAPI()
100
- adapter = RESTAdapter(registry)
101
- adapter.register_endpoints(app)
102
- ```
103
-
104
- ## Диаграммы потока данных
105
-
106
- ### Процесс регистрации команды
107
-
108
- ```
109
- ┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
110
- │ │ │ │ │ │
111
- │ Python функция ├─────►│ Metadata Extractor ├─────►│ Метаданные │
112
- │ │ │ │ │ │
113
- └─────────────────┘ └────────────────────┘ └────────┬────────┘
114
-
115
-
116
- ┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
117
- │ │ │ │ │ │
118
- │ CommandRegistry│◄─────┤ Валидация данных │◄─────┤ Параметры │
119
- │ │ │ │ │ │
120
- └────────┬────────┘ └────────────────────┘ └─────────────────┘
121
-
122
-
123
- ┌─────────────────┐
124
- │ │
125
- │ Dispatcher │
126
- │ │
127
- └─────────────────┘
128
- ```
129
-
130
- ### Процесс выполнения команды
131
-
132
- ```
133
- ┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
134
- │ │ │ │ │ │
135
- │ Имя команды │ │ │ │ Валидация │
136
- │ + параметры ├─────►│ CommandRegistry ├─────►│ параметров │
137
- │ │ │ │ │ │
138
- └─────────────────┘ └────────────────────┘ └────────┬────────┘
139
-
140
-
141
- ┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
142
- │ │ │ │ │ │
143
- │ Результат │◄─────┤ Обработка ошибок │◄─────┤ Dispatcher │
144
- │ │ │ │ │ (выполнение) │
145
- └─────────────────┘ └────────────────────┘ └─────────────────┘
146
- ```
147
-
148
- ### Генерация документации API
149
-
150
- ```
151
- ┌─────────────────┐ ┌────────────────────┐ ┌─────────────────┐
152
- │ │ │ │ │ │
153
- │ Метаданные │ │ Schema Generator │ │ OpenAPI/ │
154
- │ команд ├─────►│ ├─────►│ JSON Schema │
155
- │ │ │ │ │ │
156
- └─────────────────┘ └────────────────────┘ └────────┬────────┘
157
-
158
-
159
- ┌─────────────────┐
160
- │ │
161
- │ API Docs UI │
162
- │ (Swagger/ │
163
- │ ReDoc) │
164
- └─────────────────┘
165
- ```
166
-
167
- ## Расширение системы
168
-
169
- ### Создание собственного диспетчера
170
-
171
- ```python
172
- from command_registry.dispatchers import BaseDispatcher
173
- from typing import Dict, Any, List, Optional, Callable
174
-
175
- class MyCustomDispatcher(BaseDispatcher):
176
- def __init__(self):
177
- self._commands = {}
178
- self._info = {}
179
-
180
- def register_handler(
181
- self,
182
- command_name: str,
183
- handler: Callable,
184
- description: str = None,
185
- summary: str = None,
186
- params: Dict[str, Any] = None
187
- ) -> None:
188
- self._commands[command_name] = handler
189
- self._info[command_name] = {
190
- "description": description,
191
- "summary": summary,
192
- "params": params or {}
193
- }
194
-
195
- def execute(self, command_name: str, params: Dict[str, Any] = None) -> Any:
196
- if command_name not in self._commands:
197
- raise ValueError(f"Command '{command_name}' not found")
198
-
199
- handler = self._commands[command_name]
200
- return handler(**params or {})
201
-
202
- def get_valid_commands(self) -> List[str]:
203
- return list(self._commands.keys())
204
-
205
- def get_command_info(self, command_name: str) -> Optional[Dict[str, Any]]:
206
- return self._info.get(command_name)
207
-
208
- def get_commands_info(self) -> Dict[str, Dict[str, Any]]:
209
- return self._info
210
- ```
211
-
212
- ### Создание собственного адаптера протокола
213
-
214
- ```python
215
- from command_registry import CommandRegistry
216
- from typing import Dict, Any
217
-
218
- class GraphQLAdapter:
219
- def __init__(self, registry: CommandRegistry):
220
- self.registry = registry
221
-
222
- def generate_schema(self) -> str:
223
- """Генерирует GraphQL схему на основе метаданных команд."""
224
- commands_info = self.registry.get_all_commands_info()
225
- schema_types = []
226
- query_fields = []
227
-
228
- for cmd_name, info in commands_info.items():
229
- # Генерация типов для входных и выходных данных
230
- input_type = self._generate_input_type(cmd_name, info["params"])
231
- output_type = self._generate_output_type(cmd_name, info.get("returns"))
232
-
233
- schema_types.extend([input_type, output_type])
234
-
235
- # Добавление поля в Query
236
- query_fields.append(
237
- f"{cmd_name}(input: {cmd_name}Input): {cmd_name}Output"
238
- )
239
-
240
- # Формирование итоговой схемы
241
- schema = "\n".join(schema_types)
242
- schema += f"\ntype Query {{\n {chr(10).join(query_fields)}\n}}"
243
-
244
- return schema
245
-
246
- def _generate_input_type(self, cmd_name: str, params: Dict[str, Any]) -> str:
247
- fields = []
248
- for name, param_info in params.items():
249
- field_type = self._map_type(param_info.get("type", "String"))
250
- required = "!" if param_info.get("required", False) else ""
251
- fields.append(f" {name}: {field_type}{required}")
252
-
253
- return f"input {cmd_name}Input {{\n{chr(10).join(fields)}\n}}"
254
-
255
- def _generate_output_type(self, cmd_name: str, returns_info: Dict[str, Any]) -> str:
256
- return_type = "String"
257
- if returns_info:
258
- return_type = self._map_type(returns_info.get("type", "String"))
259
-
260
- return (
261
- f"type {cmd_name}Output {{\n"
262
- f" result: {return_type}\n"
263
- f" error: String\n"
264
- f"}}"
265
- )
266
-
267
- def _map_type(self, python_type: str) -> str:
268
- """Преобразует типы Python в типы GraphQL."""
269
- type_mapping = {
270
- "str": "String",
271
- "int": "Int",
272
- "float": "Float",
273
- "bool": "Boolean",
274
- "list": "List",
275
- "dict": "JSON",
276
- # Добавьте другие маппинги по необходимости
277
- }
278
- return type_mapping.get(python_type, "String")
279
- ```
280
-
281
- ## Лучшие практики
282
-
283
- ### Организация команд в модули
284
-
285
- Рекомендуется группировать связанные команды в модули по их функциональности:
286
-
287
- ```
288
- commands/
289
- ├── __init__.py
290
- ├── user_commands.py # Команды для работы с пользователями
291
- ├── product_commands.py # Команды для работы с товарами
292
- └── order_commands.py # Команды для работы с заказами
293
- ```
294
-
295
- ### Регистрация команд
296
-
297
- Автоматическая регистрация из модуля:
298
-
299
- ```python
300
- registry.scan_module("myapp.commands")
301
- ```
302
-
303
- Ручная регистрация отдельных функций:
304
-
305
- ```python
306
- from myapp.commands.user_commands import create_user, update_user, delete_user
307
-
308
- registry.register_command("create_user", create_user)
309
- registry.register_command("update_user", update_user)
310
- registry.register_command("delete_user", delete_user)
311
- ```
312
-
313
- ### Обработка ошибок
314
-
315
- ```python
316
- def divide_numbers(a: float, b: float) -> float:
317
- """
318
- Делит число a на число b.
319
-
320
- Args:
321
- a: Делимое
322
- b: Делитель (не должен быть равен 0)
323
-
324
- Returns:
325
- Результат деления a на b
326
-
327
- Raises:
328
- ValueError: Если делитель равен 0
329
- """
330
- if b == 0:
331
- raise ValueError("Делитель не может быть равен 0")
332
- return a / b
333
- ```
334
-
335
- ## Заключение
336
-
337
- Архитектура Command Registry обеспечивает:
338
-
339
- 1. **Четкое разделение ответственности** между компонентами системы
340
- 2. **Расширяемость** через добавление новых диспетчеров и адаптеров
341
- 3. **Простоту использования** для разработчиков команд
342
- 4. **Автоматизацию** извлечения метаданных и валидации
343
- 5. **Интероперабельность** с различными протоколами и форматами
@@ -1,250 +0,0 @@
1
- # Command Development Guide
2
-
3
- This guide describes best practices and recommendations for developing commands for the Command Registry system.
4
-
5
- ## Core Principles
6
-
7
- When developing commands for Command Registry, follow these principles:
8
-
9
- 1. **Single Responsibility**: a command should do one thing and do it well
10
- 2. **Declarative**: a command should be self-documenting through type hints and docstrings
11
- 3. **Independence**: a command should not depend on other commands
12
- 4. **Idempotency**: repeated execution of a command with the same parameters should yield identical results
13
- 5. **Validation**: a command should validate input data before execution
14
-
15
- ## Command Structure
16
-
17
- Recommended command structure:
18
-
19
- ```python
20
- from typing import Dict, List, Optional, Any, Union, Tuple
21
- import logging
22
-
23
- logger = logging.getLogger(__name__)
24
-
25
- def command_name(
26
- required_param: str,
27
- optional_param: Optional[int] = None,
28
- *,
29
- keyword_only_param: bool = False
30
- ) -> Dict[str, Any]:
31
- """
32
- Brief command description (one sentence).
33
-
34
- Detailed command description explaining its purpose,
35
- operational features, and possible side effects.
36
-
37
- Args:
38
- required_param: Description of required parameter
39
- optional_param: Description of optional parameter
40
- keyword_only_param: Description of keyword-only parameter
41
-
42
- Returns:
43
- Description of return value
44
-
45
- Raises:
46
- ValueError: When validation error occurs
47
- RuntimeError: When execution error occurs
48
-
49
- Examples:
50
- >>> command_name("value", 42, keyword_only_param=True)
51
- {'status': 'success', 'result': 'value_processed'}
52
- """
53
- # Log execution start
54
- logger.debug(f"Executing command_name with params: {required_param}, {optional_param}, {keyword_only_param}")
55
-
56
- # Parameter validation
57
- if not required_param:
58
- raise ValueError("required_param cannot be empty")
59
-
60
- if optional_param is not None and optional_param < 0:
61
- raise ValueError("optional_param must be non-negative")
62
-
63
- # Execute main logic
64
- try:
65
- # Main command logic
66
- result = process_data(required_param, optional_param, keyword_only_param)
67
-
68
- # Log successful execution
69
- logger.info(f"Command command_name executed successfully with result: {result}")
70
-
71
- return {
72
- "status": "success",
73
- "result": result
74
- }
75
- except Exception as e:
76
- # Log error
77
- logger.error(f"Error executing command command_name: {str(e)}", exc_info=True)
78
-
79
- # Propagate exception for handling above
80
- raise RuntimeError(f"Failed to execute command: {str(e)}") from e
81
- ```
82
-
83
- ## Best Practices
84
-
85
- ### Type Hints
86
-
87
- 1. **Use type hints for all parameters and return values**:
88
-
89
- ```python
90
- def process_data(data: List[Dict[str, Any]], limit: Optional[int] = None) -> Tuple[List[Dict[str, Any]], int]:
91
- # ...
92
- ```
93
-
94
- 2. **Use complex types from the `typing` module**:
95
-
96
- ```python
97
- from typing import Dict, List, Optional, Union, Callable, TypeVar, Generic
98
-
99
- T = TypeVar('T')
100
-
101
- def filter_items(
102
- items: List[T],
103
- predicate: Callable[[T], bool]
104
- ) -> List[T]:
105
- # ...
106
- ```
107
-
108
- 3. **Define your own types for complex structures**:
109
-
110
- ```python
111
- from typing import Dict, List, TypedDict, Optional
112
-
113
- class UserData(TypedDict):
114
- id: str
115
- name: str
116
- email: str
117
- roles: List[str]
118
- profile: Optional[Dict[str, str]]
119
-
120
- def get_user(user_id: str) -> UserData:
121
- # ...
122
- ```
123
-
124
- ### Documentation
125
-
126
- 1. **Use docstrings to describe the command, its parameters, and return value**:
127
-
128
- ```python
129
- def calculate_total(prices: List[float], discount: float = 0.0) -> float:
130
- """
131
- Calculates total cost with discount.
132
-
133
- Args:
134
- prices: List of item prices
135
- discount: Discount percentage (from 0.0 to 1.0)
136
-
137
- Returns:
138
- Total cost with discount
139
-
140
- Raises:
141
- ValueError: If discount is not in range [0, 1]
142
- """
143
- ```
144
-
145
- 2. **Add usage examples in docstring**:
146
-
147
- ```python
148
- def calculate_total(prices: List[float], discount: float = 0.0) -> float:
149
- """
150
- ...
151
-
152
- Examples:
153
- >>> calculate_total([10.0, 20.0, 30.0])
154
- 60.0
155
- >>> calculate_total([10.0, 20.0, 30.0], discount=0.1)
156
- 54.0
157
- """
158
- ```
159
-
160
- ### Parameter Validation
161
-
162
- 1. **Check parameter correctness at the beginning of the function**:
163
-
164
- ```python
165
- def update_user(user_id: str, name: Optional[str] = None, email: Optional[str] = None) -> Dict[str, Any]:
166
- """Updates user information."""
167
- if not user_id:
168
- raise ValueError("user_id cannot be empty")
169
-
170
- if email is not None and "@" not in email:
171
- raise ValueError("Invalid email format")
172
-
173
- # Main logic...
174
- ```
175
-
176
- 2. **Use libraries for complex data validation**:
177
-
178
- ```python
179
- from pydantic import BaseModel, EmailStr, validator
180
-
181
- class UserUpdateParams(BaseModel):
182
- user_id: str
183
- name: Optional[str] = None
184
- email: Optional[EmailStr] = None
185
-
186
- @validator('user_id')
187
- def user_id_must_not_be_empty(cls, v):
188
- if not v:
189
- raise ValueError('user_id cannot be empty')
190
- return v
191
-
192
- def update_user(params: UserUpdateParams) -> Dict[str, Any]:
193
- # Pydantic has already performed validation
194
- # Main logic...
195
- ```
196
-
197
- ### Error Handling
198
-
199
- 1. **Use specific exception types**:
200
-
201
- ```python
202
- def get_user(user_id: str) -> Dict[str, Any]:
203
- if not user_id:
204
- raise ValueError("user_id cannot be empty")
205
-
206
- user = db.find_user(user_id)
207
- if user is None:
208
- raise UserNotFoundError(f"User with id {user_id} not found")
209
-
210
- return user
211
- ```
212
-
213
- 2. **Preserve error context using exception chaining**:
214
-
215
- ```python
216
- def process_order(order_id: str) -> Dict[str, Any]:
217
- try:
218
- order = get_order(order_id)
219
- # Order processing...
220
- except OrderNotFoundError as e:
221
- raise ProcessingError(f"Failed to process order {order_id}") from e
222
- except Exception as e:
223
- raise ProcessingError(f"Unexpected error while processing order {order_id}") from e
224
- ```
225
-
226
- ### Logging
227
-
228
- 1. **Use logging to track command execution progress**:
229
-
230
- ```python
231
- import logging
232
-
233
- logger = logging.getLogger(__name__)
234
-
235
- def complex_operation(data: Dict[str, Any]) -> Dict[str, Any]:
236
- logger.info(f"Starting complex operation with data: {data}")
237
-
238
- try:
239
- # Step 1
240
- logger.debug("Performing step 1")
241
- result_1 = step_1(data)
242
-
243
- # Step 2
244
- logger.debug("Performing step 2")
245
- result_2 = step_2(result_1)
246
-
247
- # Final step
248
- logger.debug("Performing final step")
249
- final_result = final_step(result_2)
250
- ```