mcp-proxy-adapter 2.0.2__py3-none-any.whl → 2.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 (67) hide show
  1. docs/README.md +172 -0
  2. docs/README_ru.md +172 -0
  3. docs/architecture.md +251 -0
  4. docs/architecture_ru.md +343 -0
  5. docs/command_development.md +250 -0
  6. docs/command_development_ru.md +593 -0
  7. docs/deployment.md +251 -0
  8. docs/deployment_ru.md +1298 -0
  9. docs/examples.md +254 -0
  10. docs/examples_ru.md +401 -0
  11. docs/mcp_proxy_adapter.md +251 -0
  12. docs/mcp_proxy_adapter_ru.md +405 -0
  13. docs/quickstart.md +251 -0
  14. docs/quickstart_ru.md +397 -0
  15. docs/testing.md +255 -0
  16. docs/testing_ru.md +469 -0
  17. docs/validation_ru.md +287 -0
  18. examples/analyze_config.py +141 -0
  19. examples/basic_integration.py +161 -0
  20. examples/docstring_and_schema_example.py +60 -0
  21. examples/extension_example.py +60 -0
  22. examples/help_best_practices.py +67 -0
  23. examples/help_usage.py +64 -0
  24. examples/mcp_proxy_client.py +131 -0
  25. examples/mcp_proxy_config.json +175 -0
  26. examples/openapi_server.py +369 -0
  27. examples/project_structure_example.py +47 -0
  28. examples/testing_example.py +53 -0
  29. mcp_proxy_adapter/__init__.py +1 -1
  30. mcp_proxy_adapter/models.py +19 -19
  31. {mcp_proxy_adapter-2.0.2.dist-info → mcp_proxy_adapter-2.1.1.dist-info}/METADATA +47 -13
  32. mcp_proxy_adapter-2.1.1.dist-info/RECORD +61 -0
  33. {mcp_proxy_adapter-2.0.2.dist-info → mcp_proxy_adapter-2.1.1.dist-info}/WHEEL +1 -1
  34. mcp_proxy_adapter-2.1.1.dist-info/top_level.txt +5 -0
  35. scripts/code_analyzer/code_analyzer.py +328 -0
  36. scripts/code_analyzer/register_commands.py +446 -0
  37. scripts/publish.py +85 -0
  38. tests/conftest.py +12 -0
  39. tests/test_adapter.py +529 -0
  40. tests/test_adapter_coverage.py +274 -0
  41. tests/test_basic_dispatcher.py +169 -0
  42. tests/test_command_registry.py +328 -0
  43. tests/test_examples.py +32 -0
  44. tests/test_mcp_proxy_adapter.py +568 -0
  45. tests/test_mcp_proxy_adapter_basic.py +262 -0
  46. tests/test_part1.py +348 -0
  47. tests/test_part2.py +524 -0
  48. tests/test_schema.py +358 -0
  49. tests/test_simple_adapter.py +251 -0
  50. mcp_proxy_adapter/adapters/__init__.py +0 -16
  51. mcp_proxy_adapter/cli/__init__.py +0 -12
  52. mcp_proxy_adapter/cli/__main__.py +0 -79
  53. mcp_proxy_adapter/cli/command_runner.py +0 -233
  54. mcp_proxy_adapter/generators/__init__.py +0 -14
  55. mcp_proxy_adapter/generators/endpoint_generator.py +0 -172
  56. mcp_proxy_adapter/generators/openapi_generator.py +0 -254
  57. mcp_proxy_adapter/generators/rest_api_generator.py +0 -207
  58. mcp_proxy_adapter/openapi_schema/__init__.py +0 -38
  59. mcp_proxy_adapter/openapi_schema/command_registry.py +0 -312
  60. mcp_proxy_adapter/openapi_schema/rest_schema.py +0 -510
  61. mcp_proxy_adapter/openapi_schema/rpc_generator.py +0 -307
  62. mcp_proxy_adapter/openapi_schema/rpc_schema.py +0 -416
  63. mcp_proxy_adapter/validators/__init__.py +0 -14
  64. mcp_proxy_adapter/validators/base_validator.py +0 -23
  65. mcp_proxy_adapter-2.0.2.dist-info/RECORD +0 -33
  66. mcp_proxy_adapter-2.0.2.dist-info/top_level.txt +0 -1
  67. {mcp_proxy_adapter-2.0.2.dist-info → mcp_proxy_adapter-2.1.1.dist-info}/licenses/LICENSE +0 -0
docs/examples.md ADDED
@@ -0,0 +1,254 @@
1
+ # Command Registry Usage Examples
2
+
3
+ This section provides practical examples of using Command Registry for various scenarios.
4
+
5
+ ## Contents
6
+
7
+ - [Basic Examples](#basic-examples)
8
+ - [FastAPI Integration](#fastapi-integration)
9
+ - [JSON-RPC Integration](#json-rpc-integration)
10
+ - [Creating CLI](#creating-cli)
11
+ - [Complete Project Example](#complete-project-example)
12
+
13
+ ## Basic Examples
14
+
15
+ ### Example 1: Creating and Registering a Command
16
+
17
+ ```python
18
+ from typing import Dict, Any, List
19
+
20
+ # Create a simple command
21
+ def search_by_keywords(keywords: List[str], limit: int = 10) -> Dict[str, Any]:
22
+ """
23
+ Search records by keywords.
24
+
25
+ Args:
26
+ keywords: List of keywords
27
+ limit: Maximum number of results
28
+
29
+ Returns:
30
+ Dict[str, Any]: Search results
31
+ """
32
+ # Here would be real search code
33
+ results = [
34
+ {"id": 1, "title": "Result 1", "score": 0.95},
35
+ {"id": 2, "title": "Result 2", "score": 0.87}
36
+ ]
37
+ return {"results": results[:limit], "total": len(results)}
38
+
39
+ # Register the command
40
+ from command_registry import CommandRegistry
41
+
42
+ registry = CommandRegistry()
43
+ registry.register_command("search_by_keywords", search_by_keywords)
44
+
45
+ # Execute the command
46
+ result = registry.dispatcher.execute(
47
+ "search_by_keywords",
48
+ keywords=["python", "api"],
49
+ limit=5
50
+ )
51
+ print(result)
52
+ ```
53
+
54
+ ### Example 2: Using Metadata Dictionary
55
+
56
+ ```python
57
+ # Command with explicit metadata
58
+ def filter_data(filter_params: Dict[str, Any]) -> Dict[str, Any]:
59
+ """Filter data by parameters"""
60
+ # Implementation...
61
+ pass
62
+
63
+ # Command metadata dictionary
64
+ COMMAND = {
65
+ "description": "Filter data by various parameters",
66
+ "parameters": {
67
+ "filter_params": {
68
+ "type": "object",
69
+ "description": "Filter parameters",
70
+ "required": True,
71
+ "properties": {
72
+ "date_from": {
73
+ "type": "string",
74
+ "format": "date",
75
+ "description": "Start date (YYYY-MM-DD)"
76
+ },
77
+ "date_to": {
78
+ "type": "string",
79
+ "format": "date",
80
+ "description": "End date (YYYY-MM-DD)"
81
+ },
82
+ "categories": {
83
+ "type": "array",
84
+ "items": {"type": "string"},
85
+ "description": "List of categories"
86
+ }
87
+ }
88
+ }
89
+ },
90
+ "responses": {
91
+ "success": {
92
+ "description": "Filtered data",
93
+ "schema": {
94
+ "type": "object",
95
+ "properties": {
96
+ "results": {
97
+ "type": "array",
98
+ "items": {"type": "object"}
99
+ },
100
+ "total": {"type": "integer"}
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## FastAPI Integration
109
+
110
+ ### Creating REST API Based on Commands
111
+
112
+ ```python
113
+ from fastapi import FastAPI
114
+ from command_registry import CommandRegistry
115
+ from command_registry.generators import RestApiGenerator
116
+
117
+ # Create FastAPI application
118
+ app = FastAPI(title="Example API")
119
+
120
+ # Create command registry
121
+ registry = CommandRegistry()
122
+
123
+ # Specify modules to search for commands
124
+ registry.scan_modules(["commands.search", "commands.filter"])
125
+
126
+ # Register all commands
127
+ registry.register_all_commands()
128
+
129
+ # Create REST API generator
130
+ rest_generator = RestApiGenerator(app)
131
+
132
+ # Generate endpoints for all commands
133
+ endpoints = rest_generator.generate_all_endpoints()
134
+
135
+ # Information about created endpoints
136
+ print(f"Created {len(endpoints)} REST endpoints:")
137
+ for endpoint in endpoints:
138
+ print(f"- {endpoint}")
139
+
140
+ # Run the application
141
+ if __name__ == "__main__":
142
+ import uvicorn
143
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
144
+ ```
145
+
146
+ This approach will automatically create REST endpoints for all your commands:
147
+
148
+ ```
149
+ GET /help # API Help
150
+ POST /search_by_keywords # Search by keywords
151
+ POST /filter_data # Filter data
152
+ ```
153
+
154
+ ## JSON-RPC Integration
155
+
156
+ ### Creating JSON-RPC Server
157
+
158
+ ```python
159
+ from fastapi import FastAPI, Request
160
+ from fastapi.responses import JSONResponse
161
+ from pydantic import BaseModel
162
+ from typing import Dict, Any, Optional
163
+
164
+ from command_registry import CommandRegistry
165
+
166
+ # Create FastAPI application
167
+ app = FastAPI(title="JSON-RPC API")
168
+
169
+ # Create command registry
170
+ registry = CommandRegistry()
171
+
172
+ # Register commands
173
+ registry.scan_modules(["commands"])
174
+ registry.register_all_commands()
175
+
176
+ # JSON-RPC request model
177
+ class JsonRpcRequest(BaseModel):
178
+ jsonrpc: str = "2.0"
179
+ method: str
180
+ params: Optional[Dict[str, Any]] = None
181
+ id: Optional[str] = None
182
+
183
+ # Endpoint for handling JSON-RPC requests
184
+ @app.post("/rpc")
185
+ async def rpc_endpoint(request: JsonRpcRequest):
186
+ try:
187
+ # Extract request parameters
188
+ method = request.method
189
+ params = request.params or {}
190
+ req_id = request.id
191
+
192
+ # Check if command exists
193
+ if method not in registry.dispatcher.get_valid_commands():
194
+ return JSONResponse(content={
195
+ "jsonrpc": "2.0",
196
+ "error": {
197
+ "code": -32601,
198
+ "message": "Method not found"
199
+ },
200
+ "id": req_id
201
+ })
202
+
203
+ # Execute command
204
+ result = registry.dispatcher.execute(method, **params)
205
+
206
+ # Return successful response
207
+ return JSONResponse(content={
208
+ "jsonrpc": "2.0",
209
+ "result": result,
210
+ "id": req_id
211
+ })
212
+ except Exception as e:
213
+ # Return error
214
+ return JSONResponse(content={
215
+ "jsonrpc": "2.0",
216
+ "error": {
217
+ "code": -32000,
218
+ "message": str(e)
219
+ },
220
+ "id": request.id
221
+ })
222
+
223
+ # Run the application
224
+ if __name__ == "__main__":
225
+ import uvicorn
226
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
227
+ ```
228
+
229
+ Example of using JSON-RPC API:
230
+
231
+ ```json
232
+ // Request
233
+ {
234
+ "jsonrpc": "2.0",
235
+ "method": "search_by_keywords",
236
+ "params": {
237
+ "keywords": ["python", "api"],
238
+ "limit": 5
239
+ },
240
+ "id": "1"
241
+ }
242
+
243
+ // Response
244
+ {
245
+ "jsonrpc": "2.0",
246
+ "result": {
247
+ "results": [
248
+ {"id": 1, "title": "Result 1", "score": 0.95},
249
+ {"id": 2, "title": "Result 2", "score": 0.87}
250
+ ],
251
+ "total": 2
252
+ },
253
+ "id": "1"
254
+ }
docs/examples_ru.md ADDED
@@ -0,0 +1,401 @@
1
+ # Примеры использования Command Registry
2
+
3
+ В этом разделе приведены практические примеры использования Command Registry для различных сценариев.
4
+
5
+ ## Содержание
6
+
7
+ - [Базовые примеры](#базовые-примеры)
8
+ - [Интеграция с FastAPI](#интеграция-с-fastapi)
9
+ - [Интеграция с JSON-RPC](#интеграция-с-json-rpc)
10
+ - [Создание CLI](#создание-cli)
11
+ - [Полный пример проекта](#полный-пример-проекта)
12
+
13
+ ## Базовые примеры
14
+
15
+ ### Пример 1: Создание и регистрация команды
16
+
17
+ ```python
18
+ from typing import Dict, Any, List
19
+
20
+ # Создаем простую команду
21
+ def search_by_keywords(keywords: List[str], limit: int = 10) -> Dict[str, Any]:
22
+ """
23
+ Поиск записей по ключевым словам.
24
+
25
+ Args:
26
+ keywords: Список ключевых слов
27
+ limit: Максимальное количество результатов
28
+
29
+ Returns:
30
+ Dict[str, Any]: Результаты поиска
31
+ """
32
+ # Здесь был бы реальный код поиска
33
+ results = [
34
+ {"id": 1, "title": "Результат 1", "score": 0.95},
35
+ {"id": 2, "title": "Результат 2", "score": 0.87}
36
+ ]
37
+ return {"results": results[:limit], "total": len(results)}
38
+
39
+ # Регистрируем команду
40
+ from command_registry import CommandRegistry
41
+
42
+ registry = CommandRegistry()
43
+ registry.register_command("search_by_keywords", search_by_keywords)
44
+
45
+ # Выполняем команду
46
+ result = registry.dispatcher.execute(
47
+ "search_by_keywords",
48
+ keywords=["python", "api"],
49
+ limit=5
50
+ )
51
+ print(result)
52
+ ```
53
+
54
+ ### Пример 2: Использование словаря метаданных
55
+
56
+ ```python
57
+ # Команда с явными метаданными
58
+ def filter_data(filter_params: Dict[str, Any]) -> Dict[str, Any]:
59
+ """Фильтрация данных по параметрам"""
60
+ # Реализация...
61
+ pass
62
+
63
+ # Словарь с метаданными команды
64
+ COMMAND = {
65
+ "description": "Фильтрация данных по различным параметрам",
66
+ "parameters": {
67
+ "filter_params": {
68
+ "type": "object",
69
+ "description": "Параметры фильтрации",
70
+ "required": True,
71
+ "properties": {
72
+ "date_from": {
73
+ "type": "string",
74
+ "format": "date",
75
+ "description": "Начальная дата (YYYY-MM-DD)"
76
+ },
77
+ "date_to": {
78
+ "type": "string",
79
+ "format": "date",
80
+ "description": "Конечная дата (YYYY-MM-DD)"
81
+ },
82
+ "categories": {
83
+ "type": "array",
84
+ "items": {"type": "string"},
85
+ "description": "Список категорий"
86
+ }
87
+ }
88
+ }
89
+ },
90
+ "responses": {
91
+ "success": {
92
+ "description": "Отфильтрованные данные",
93
+ "schema": {
94
+ "type": "object",
95
+ "properties": {
96
+ "results": {
97
+ "type": "array",
98
+ "items": {"type": "object"}
99
+ },
100
+ "total": {"type": "integer"}
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ ## Интеграция с FastAPI
109
+
110
+ ### Создание REST API на основе команд
111
+
112
+ ```python
113
+ from fastapi import FastAPI
114
+ from command_registry import CommandRegistry
115
+ from command_registry.generators import RestApiGenerator
116
+
117
+ # Создаем приложение FastAPI
118
+ app = FastAPI(title="Example API")
119
+
120
+ # Создаем реестр команд
121
+ registry = CommandRegistry()
122
+
123
+ # Указываем модули для поиска команд
124
+ registry.scan_modules(["commands.search", "commands.filter"])
125
+
126
+ # Регистрируем все команды
127
+ registry.register_all_commands()
128
+
129
+ # Создаем генератор REST API
130
+ rest_generator = RestApiGenerator(app)
131
+
132
+ # Генерируем эндпоинты для всех команд
133
+ endpoints = rest_generator.generate_all_endpoints()
134
+
135
+ # Информация о созданных эндпоинтах
136
+ print(f"Created {len(endpoints)} REST endpoints:")
137
+ for endpoint in endpoints:
138
+ print(f"- {endpoint}")
139
+
140
+ # Запускаем приложение
141
+ if __name__ == "__main__":
142
+ import uvicorn
143
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
144
+ ```
145
+
146
+ Такой подход автоматически создаст REST эндпоинты для всех ваших команд:
147
+
148
+ ```
149
+ GET /help # Справка по API
150
+ POST /search_by_keywords # Поиск по ключевым словам
151
+ POST /filter_data # Фильтрация данных
152
+ ```
153
+
154
+ ## Интеграция с JSON-RPC
155
+
156
+ ### Создание JSON-RPC сервера
157
+
158
+ ```python
159
+ from fastapi import FastAPI, Request
160
+ from fastapi.responses import JSONResponse
161
+ from pydantic import BaseModel
162
+ from typing import Dict, Any, Optional
163
+
164
+ from command_registry import CommandRegistry
165
+
166
+ # Создаем приложение FastAPI
167
+ app = FastAPI(title="JSON-RPC API")
168
+
169
+ # Создаем реестр команд
170
+ registry = CommandRegistry()
171
+
172
+ # Регистрируем команды
173
+ registry.scan_modules(["commands"])
174
+ registry.register_all_commands()
175
+
176
+ # Модель для JSON-RPC запроса
177
+ class JsonRpcRequest(BaseModel):
178
+ jsonrpc: str = "2.0"
179
+ method: str
180
+ params: Optional[Dict[str, Any]] = None
181
+ id: Optional[str] = None
182
+
183
+ # Эндпоинт для обработки JSON-RPC запросов
184
+ @app.post("/rpc")
185
+ async def rpc_endpoint(request: JsonRpcRequest):
186
+ try:
187
+ # Извлекаем параметры запроса
188
+ method = request.method
189
+ params = request.params or {}
190
+ req_id = request.id
191
+
192
+ # Проверяем, что команда существует
193
+ if method not in registry.dispatcher.get_valid_commands():
194
+ return JSONResponse(content={
195
+ "jsonrpc": "2.0",
196
+ "error": {
197
+ "code": -32601,
198
+ "message": "Method not found"
199
+ },
200
+ "id": req_id
201
+ })
202
+
203
+ # Выполняем команду
204
+ result = registry.dispatcher.execute(method, **params)
205
+
206
+ # Возвращаем успешный ответ
207
+ return JSONResponse(content={
208
+ "jsonrpc": "2.0",
209
+ "result": result,
210
+ "id": req_id
211
+ })
212
+ except Exception as e:
213
+ # Возвращаем ошибку
214
+ return JSONResponse(content={
215
+ "jsonrpc": "2.0",
216
+ "error": {
217
+ "code": -32000,
218
+ "message": str(e)
219
+ },
220
+ "id": request.id
221
+ })
222
+
223
+ # Запускаем приложение
224
+ if __name__ == "__main__":
225
+ import uvicorn
226
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
227
+ ```
228
+
229
+ Пример использования JSON-RPC API:
230
+
231
+ ```json
232
+ // Запрос
233
+ {
234
+ "jsonrpc": "2.0",
235
+ "method": "search_by_keywords",
236
+ "params": {
237
+ "keywords": ["python", "api"],
238
+ "limit": 5
239
+ },
240
+ "id": "1"
241
+ }
242
+
243
+ // Ответ
244
+ {
245
+ "jsonrpc": "2.0",
246
+ "result": {
247
+ "results": [
248
+ {"id": 1, "title": "Результат 1", "score": 0.95},
249
+ {"id": 2, "title": "Результат 2", "score": 0.87}
250
+ ],
251
+ "total": 2
252
+ },
253
+ "id": "1"
254
+ }
255
+ ```
256
+
257
+ ## Создание CLI
258
+
259
+ ### Создание интерфейса командной строки
260
+
261
+ ```python
262
+ from command_registry import CommandRegistry
263
+ from command_registry.cli import CommandRunner
264
+
265
+ # Создаем реестр команд
266
+ registry = CommandRegistry()
267
+
268
+ # Регистрируем команды
269
+ registry.scan_modules(["commands"])
270
+ registry.register_all_commands()
271
+
272
+ # Создаем CommandRunner
273
+ runner = CommandRunner(registry.dispatcher)
274
+
275
+ # Запускаем CLI
276
+ if __name__ == "__main__":
277
+ import sys
278
+ runner.run(sys.argv[1:])
279
+ ```
280
+
281
+ Использование CLI:
282
+
283
+ ```bash
284
+ # Получение списка команд
285
+ python cli.py
286
+
287
+ # Справка по конкретной команде
288
+ python cli.py help search_by_keywords
289
+
290
+ # Выполнение команды
291
+ python cli.py search_by_keywords --keywords='["python", "api"]' --limit=5
292
+ ```
293
+
294
+ ## Полный пример проекта
295
+
296
+ Ниже приведена структура полного проекта, использующего Command Registry:
297
+
298
+ ```
299
+ project/
300
+ ├── commands/
301
+ │ ├── __init__.py
302
+ │ ├── search/
303
+ │ │ ├── __init__.py
304
+ │ │ ├── search_by_keywords.py
305
+ │ │ └── search_by_vector.py
306
+ │ └── data/
307
+ │ ├── __init__.py
308
+ │ ├── filter_data.py
309
+ │ └── add_data.py
310
+ ├── api/
311
+ │ ├── __init__.py
312
+ │ ├── rest.py
313
+ │ └── json_rpc.py
314
+ ├── cli/
315
+ │ ├── __init__.py
316
+ │ └── main.py
317
+ ├── app.py
318
+ └── main.py
319
+ ```
320
+
321
+ ### app.py
322
+
323
+ ```python
324
+ from command_registry import CommandRegistry
325
+ from command_registry.generators import RestApiGenerator, OpenApiGenerator
326
+ from fastapi import FastAPI
327
+
328
+ # Создаем приложение FastAPI
329
+ app = FastAPI(title="API Example", version="1.0.0")
330
+
331
+ def register_commands(strict: bool = True):
332
+ """
333
+ Регистрирует все команды в диспетчере.
334
+
335
+ Args:
336
+ strict: Если True, прерывает регистрацию при ошибках в документации
337
+ """
338
+ # Создаем реестр команд
339
+ registry = CommandRegistry(strict=strict)
340
+
341
+ # Сканируем модули с командами
342
+ registry.scan_modules([
343
+ "commands.search",
344
+ "commands.data"
345
+ ])
346
+
347
+ # Создаем генератор REST API
348
+ rest_generator = RestApiGenerator(app)
349
+ registry.add_generator(rest_generator)
350
+
351
+ # Создаем генератор OpenAPI схемы
352
+ openapi_generator = OpenApiGenerator()
353
+ registry.add_generator(openapi_generator)
354
+
355
+ # Регистрируем все команды
356
+ result = registry.register_all_commands()
357
+
358
+ # Генерируем REST эндпоинты
359
+ rest_generator.generate_all_endpoints()
360
+
361
+ # Устанавливаем схему OpenAPI
362
+ app.openapi = lambda: openapi_generator.generate_schema()
363
+
364
+ return registry, result
365
+
366
+ # Регистрируем команды при импорте
367
+ registry, result = register_commands(strict=True)
368
+ ```
369
+
370
+ ### main.py
371
+
372
+ ```python
373
+ from app import app
374
+
375
+ if __name__ == "__main__":
376
+ import uvicorn
377
+
378
+ print("Starting API server...")
379
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
380
+ ```
381
+
382
+ ### cli/main.py
383
+
384
+ ```python
385
+ from app import registry
386
+ from command_registry.cli import CommandRunner
387
+
388
+ def main():
389
+ """
390
+ Запускает интерфейс командной строки.
391
+ """
392
+ runner = CommandRunner(registry.dispatcher)
393
+
394
+ import sys
395
+ runner.run(sys.argv[1:])
396
+
397
+ if __name__ == "__main__":
398
+ main()
399
+ ```
400
+
401
+ Такой проект предоставляет одновременно REST API, JSON-RPC API и интерфейс командной строки для одного и того же набора команд, что максимально повышает гибкость и переиспользование кода.