mcp-proxy-adapter 2.1.0__py3-none-any.whl → 2.1.2__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 (78) 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 +17 -0
  30. mcp_proxy_adapter/adapter.py +697 -0
  31. mcp_proxy_adapter/models.py +47 -0
  32. mcp_proxy_adapter/registry.py +439 -0
  33. mcp_proxy_adapter/schema.py +257 -0
  34. {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/METADATA +2 -2
  35. mcp_proxy_adapter-2.1.2.dist-info/RECORD +61 -0
  36. mcp_proxy_adapter-2.1.2.dist-info/top_level.txt +5 -0
  37. scripts/code_analyzer/code_analyzer.py +328 -0
  38. scripts/code_analyzer/register_commands.py +446 -0
  39. scripts/publish.py +85 -0
  40. tests/conftest.py +12 -0
  41. tests/test_adapter.py +529 -0
  42. tests/test_adapter_coverage.py +274 -0
  43. tests/test_basic_dispatcher.py +169 -0
  44. tests/test_command_registry.py +328 -0
  45. tests/test_examples.py +32 -0
  46. tests/test_mcp_proxy_adapter.py +568 -0
  47. tests/test_mcp_proxy_adapter_basic.py +262 -0
  48. tests/test_part1.py +348 -0
  49. tests/test_part2.py +524 -0
  50. tests/test_schema.py +358 -0
  51. tests/test_simple_adapter.py +251 -0
  52. adapters/__init__.py +0 -16
  53. cli/__init__.py +0 -12
  54. cli/__main__.py +0 -79
  55. cli/command_runner.py +0 -233
  56. generators/__init__.py +0 -14
  57. generators/endpoint_generator.py +0 -172
  58. generators/openapi_generator.py +0 -254
  59. generators/rest_api_generator.py +0 -207
  60. mcp_proxy_adapter-2.1.0.dist-info/RECORD +0 -28
  61. mcp_proxy_adapter-2.1.0.dist-info/top_level.txt +0 -7
  62. openapi_schema/__init__.py +0 -38
  63. openapi_schema/command_registry.py +0 -312
  64. openapi_schema/rest_schema.py +0 -510
  65. openapi_schema/rpc_generator.py +0 -307
  66. openapi_schema/rpc_schema.py +0 -416
  67. validators/__init__.py +0 -14
  68. validators/base_validator.py +0 -23
  69. {analyzers → mcp_proxy_adapter/analyzers}/__init__.py +0 -0
  70. {analyzers → mcp_proxy_adapter/analyzers}/docstring_analyzer.py +0 -0
  71. {analyzers → mcp_proxy_adapter/analyzers}/type_analyzer.py +0 -0
  72. {dispatchers → mcp_proxy_adapter/dispatchers}/__init__.py +0 -0
  73. {dispatchers → mcp_proxy_adapter/dispatchers}/base_dispatcher.py +0 -0
  74. {dispatchers → mcp_proxy_adapter/dispatchers}/json_rpc_dispatcher.py +0 -0
  75. {validators → mcp_proxy_adapter/validators}/docstring_validator.py +0 -0
  76. {validators → mcp_proxy_adapter/validators}/metadata_validator.py +0 -0
  77. {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/WHEEL +0 -0
  78. {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,254 +0,0 @@
1
- """
2
- OpenAPI schema generator for API documentation based on registered commands.
3
- """
4
- from typing import Any, Dict, List, Optional, Callable
5
- import inspect
6
- from pydantic import BaseModel, create_model
7
-
8
- class OpenApiGenerator:
9
- """
10
- OpenAPI schema generator for API documentation based on registered commands.
11
-
12
- Creates OpenAPI schema describing all registered commands and their parameters
13
- for use in automatic API documentation.
14
- """
15
-
16
- def __init__(self, dispatcher: Any, title: str = "Vector Store API",
17
- version: str = "1.0.0", description: str = "Vector Store API Documentation"):
18
- """
19
- Initialize OpenAPI schema generator.
20
-
21
- Args:
22
- dispatcher: Command dispatcher providing access to registered commands
23
- title: API title
24
- version: API version
25
- description: API description
26
- """
27
- self.dispatcher = dispatcher
28
- self.title = title
29
- self.version = version
30
- self.description = description
31
-
32
- def generate_schema(self) -> Dict[str, Any]:
33
- """
34
- Generates complete OpenAPI schema for all registered commands.
35
-
36
- Returns:
37
- Dict[str, Any]: OpenAPI schema as dictionary
38
- """
39
- # Base OpenAPI schema structure
40
- schema = {
41
- "openapi": "3.0.0",
42
- "info": {
43
- "title": self.title,
44
- "version": self.version,
45
- "description": self.description
46
- },
47
- "paths": {},
48
- "components": {
49
- "schemas": {}
50
- }
51
- }
52
-
53
- # Get all registered commands
54
- commands = self.dispatcher.get_registered_commands()
55
-
56
- # Generate schemas for each command
57
- for command_name, command_data in commands.items():
58
- handler_func = command_data['handler']
59
- metadata = command_data.get('metadata', {})
60
-
61
- # Add path for endpoint
62
- path = f"/{command_name}"
63
- method = "post" # By default all commands are handled via POST
64
-
65
- # Get request schema
66
- request_schema = self._generate_request_schema(command_name, handler_func)
67
-
68
- # Add response schema
69
- response_schema = self._generate_response_schema(command_name, handler_func, metadata)
70
-
71
- # Add path to schema
72
- schema["paths"][path] = {
73
- method: {
74
- "summary": metadata.get('summary', f"Execute {command_name} command"),
75
- "description": metadata.get('description', ""),
76
- "operationId": f"{command_name}",
77
- "requestBody": {
78
- "required": True,
79
- "content": {
80
- "application/json": {
81
- "schema": request_schema
82
- }
83
- }
84
- },
85
- "responses": {
86
- "200": {
87
- "description": "Successful operation",
88
- "content": {
89
- "application/json": {
90
- "schema": response_schema
91
- }
92
- }
93
- },
94
- "500": {
95
- "description": "Internal server error",
96
- "content": {
97
- "application/json": {
98
- "schema": {
99
- "type": "object",
100
- "properties": {
101
- "success": {
102
- "type": "boolean",
103
- "example": False
104
- },
105
- "error": {
106
- "type": "string"
107
- }
108
- }
109
- }
110
- }
111
- }
112
- }
113
- }
114
- }
115
- }
116
-
117
- # Add /help endpoint
118
- schema["paths"]["/help"] = {
119
- "get": {
120
- "summary": "Get API help",
121
- "description": "Get list of all available commands and API endpoints",
122
- "operationId": "getHelp",
123
- "responses": {
124
- "200": {
125
- "description": "Successful operation",
126
- "content": {
127
- "application/json": {
128
- "schema": {
129
- "type": "object",
130
- "properties": {
131
- "success": {
132
- "type": "boolean",
133
- "example": True
134
- },
135
- "registered_commands": {
136
- "type": "object",
137
- "additionalProperties": {
138
- "type": "object",
139
- "properties": {
140
- "endpoint": {
141
- "type": "string"
142
- },
143
- "description": {
144
- "type": "string"
145
- },
146
- "parameters": {
147
- "type": "object"
148
- }
149
- }
150
- }
151
- },
152
- "endpoints": {
153
- "type": "array",
154
- "items": {
155
- "type": "string"
156
- }
157
- }
158
- }
159
- }
160
- }
161
- }
162
- }
163
- }
164
- }
165
- }
166
-
167
- return schema
168
-
169
- def _generate_request_schema(self, command_name: str, handler_func: Callable) -> Dict[str, Any]:
170
- """
171
- Generates request schema for specified command.
172
-
173
- Args:
174
- command_name: Command name
175
- handler_func: Command handler function
176
-
177
- Returns:
178
- Dict[str, Any]: Request schema in OpenAPI format
179
- """
180
- # Get function signature
181
- sig = inspect.signature(handler_func)
182
-
183
- # Create request schema
184
- properties = {}
185
- required = []
186
-
187
- for name, param in sig.parameters.items():
188
- # Skip self parameter
189
- if name == 'self':
190
- continue
191
-
192
- # Get parameter type
193
- param_type = param.annotation if param.annotation != inspect.Parameter.empty else Any
194
-
195
- # Determine type for OpenAPI
196
- if param_type == str:
197
- prop_type = {"type": "string"}
198
- elif param_type == int:
199
- prop_type = {"type": "integer"}
200
- elif param_type == float:
201
- prop_type = {"type": "number"}
202
- elif param_type == bool:
203
- prop_type = {"type": "boolean"}
204
- elif param_type == list or param_type == List:
205
- prop_type = {"type": "array", "items": {"type": "string"}}
206
- elif param_type == dict or param_type == Dict:
207
- prop_type = {"type": "object"}
208
- else:
209
- prop_type = {"type": "object"}
210
-
211
- # Add property to schema
212
- properties[name] = prop_type
213
-
214
- # If parameter is required, add it to required list
215
- if param.default == inspect.Parameter.empty:
216
- required.append(name)
217
-
218
- schema = {
219
- "type": "object",
220
- "properties": properties
221
- }
222
-
223
- if required:
224
- schema["required"] = required
225
-
226
- return schema
227
-
228
- def _generate_response_schema(self, command_name: str, handler_func: Callable,
229
- metadata: Dict[str, Any]) -> Dict[str, Any]:
230
- """
231
- Generates response schema for specified command.
232
-
233
- Args:
234
- command_name: Command name
235
- handler_func: Command handler function
236
- metadata: Command metadata
237
-
238
- Returns:
239
- Dict[str, Any]: Response schema in OpenAPI format
240
- """
241
- # Base response structure
242
- return {
243
- "type": "object",
244
- "properties": {
245
- "success": {
246
- "type": "boolean",
247
- "example": True
248
- },
249
- "result": {
250
- "type": "object",
251
- "description": metadata.get("returns", "Command result")
252
- }
253
- }
254
- }
@@ -1,207 +0,0 @@
1
- """
2
- Генератор REST API на основе команд и их метаданных.
3
- """
4
- from typing import Dict, Any, Optional, List, Callable
5
- import inspect
6
- import logging
7
- from command_registry.dispatchers.base_dispatcher import BaseDispatcher
8
-
9
- logger = logging.getLogger("command_registry")
10
-
11
- class RestApiGenerator:
12
- """
13
- Генератор REST API для FastAPI на основе команд.
14
-
15
- Этот класс создает REST эндпоинты для FastAPI на основе
16
- зарегистрированных команд и их метаданных.
17
- """
18
-
19
- def __init__(self, app, dispatcher: Optional[BaseDispatcher] = None, prefix: str = ""):
20
- """
21
- Инициализирует генератор REST API.
22
-
23
- Args:
24
- app: Экземпляр FastAPI приложения
25
- dispatcher: Диспетчер команд для доступа к метаданным
26
- prefix: Префикс для всех эндпоинтов (например, "/api")
27
- """
28
- self.app = app
29
- self.dispatcher = dispatcher
30
- self.prefix = prefix.rstrip("/")
31
-
32
- # Словарь для хранения соответствия между командами и эндпоинтами
33
- self._endpoints = {}
34
-
35
- def set_dispatcher(self, dispatcher: BaseDispatcher) -> None:
36
- """
37
- Устанавливает диспетчер команд.
38
-
39
- Args:
40
- dispatcher: Диспетчер команд
41
- """
42
- self.dispatcher = dispatcher
43
-
44
- def generate_endpoints(self) -> None:
45
- """
46
- Генерирует REST эндпоинты для всех команд.
47
-
48
- Создает эндпоинты для всех команд, зарегистрированных в диспетчере,
49
- включая автоматический хелп-эндпоинт.
50
- """
51
- if not self.dispatcher:
52
- logger.warning("Диспетчер команд не установлен, невозможно сгенерировать эндпоинты")
53
- return
54
-
55
- # Получаем информацию о всех командах
56
- commands_info = self.dispatcher.get_commands_info()
57
-
58
- # Генерируем эндпоинты для каждой команды
59
- for command, info in commands_info.items():
60
- # Генерируем путь для эндпоинта
61
- path = f"{self.prefix}/{command.replace('_', '-')}"
62
-
63
- # Генерируем обработчик для эндпоинта
64
- endpoint = self._create_endpoint_handler(command, info)
65
-
66
- # Регистрируем эндпоинт в FastAPI
67
- self.app.post(
68
- path,
69
- summary=info.get("summary", command),
70
- description=info.get("description", ""),
71
- tags=self._get_tags_for_command(command)
72
- )(endpoint)
73
-
74
- # Сохраняем соответствие между командой и эндпоинтом
75
- self._endpoints[command] = path
76
-
77
- logger.debug(f"Сгенерирован REST эндпоинт для команды '{command}': {path}")
78
-
79
- # Генерируем хелп-эндпоинт
80
- self._generate_help_endpoint()
81
-
82
- def _create_endpoint_handler(self, command: str, info: Dict[str, Any]) -> Callable:
83
- """
84
- Создает функцию-обработчик для эндпоинта.
85
-
86
- Args:
87
- command: Имя команды
88
- info: Метаданные команды
89
-
90
- Returns:
91
- Callable: Функция-обработчик для FastAPI
92
- """
93
- dispatcher = self.dispatcher
94
-
95
- # Создаем динамическую функцию-обработчик
96
- async def endpoint(**kwargs):
97
- try:
98
- # Выполняем команду через диспетчер
99
- result = dispatcher.execute(command, **kwargs)
100
-
101
- # Если результат корутина, ожидаем его завершения
102
- if inspect.iscoroutine(result):
103
- result = await result
104
-
105
- return result
106
- except Exception as e:
107
- # В случае ошибки возвращаем структурированный ответ с ошибкой
108
- return {
109
- "error": {
110
- "message": str(e),
111
- "code": 500
112
- }
113
- }
114
-
115
- # Устанавливаем имя функции и докстринг
116
- endpoint.__name__ = f"{command}_endpoint"
117
- endpoint.__doc__ = info.get("description", "")
118
-
119
- # Возвращаем функцию-обработчик
120
- return endpoint
121
-
122
- def _generate_help_endpoint(self) -> None:
123
- """
124
- Генерирует хелп-эндпоинт для API.
125
-
126
- Создает специальный эндпоинт /help, который возвращает информацию
127
- о всех доступных командах и их эндпоинтах.
128
- """
129
- app = self.app
130
- dispatcher = self.dispatcher
131
- endpoints = self._endpoints
132
-
133
- # Путь для хелп-эндпоинта
134
- help_path = f"{self.prefix}/help"
135
-
136
- # Функция-обработчик для хелп-эндпоинта
137
- async def help_endpoint(command: Optional[str] = None):
138
- if command:
139
- # Если указана конкретная команда, возвращаем информацию о ней
140
- command_info = dispatcher.get_command_info(command)
141
- if not command_info:
142
- return {
143
- "error": f"Команда '{command}' не найдена",
144
- "available_commands": list(dispatcher.get_valid_commands())
145
- }
146
-
147
- # Добавляем URL эндпоинта
148
- endpoint_url = endpoints.get(command)
149
- if endpoint_url:
150
- command_info["endpoint"] = endpoint_url
151
-
152
- return {
153
- "command": command,
154
- "info": command_info
155
- }
156
-
157
- # Иначе возвращаем информацию о всех командах
158
- commands_info = {}
159
- for cmd, info in dispatcher.get_commands_info().items():
160
- endpoint_url = endpoints.get(cmd)
161
- commands_info[cmd] = {
162
- "summary": info.get("summary", ""),
163
- "description": info.get("description", ""),
164
- "endpoint": endpoint_url,
165
- "params_count": len(info.get("params", {}))
166
- }
167
-
168
- return {
169
- "commands": commands_info,
170
- "total": len(commands_info),
171
- "base_url": self.prefix,
172
- "note": "Для получения подробной информации о команде используйте параметр 'command'"
173
- }
174
-
175
- # Регистрируем хелп-эндпоинт в FastAPI
176
- app.get(
177
- help_path,
178
- summary="API справка",
179
- description="Возвращает информацию о доступных командах и эндпоинтах API",
180
- tags=["help"]
181
- )(help_endpoint)
182
-
183
- logger.debug(f"Сгенерирован хелп-эндпоинт: {help_path}")
184
-
185
- def _get_tags_for_command(self, command: str) -> List[str]:
186
- """
187
- Определяет теги для команды.
188
-
189
- Args:
190
- command: Имя команды
191
-
192
- Returns:
193
- List[str]: Список тегов для документации OpenAPI
194
- """
195
- # Простая эвристика для определения категории команды
196
- if command.startswith(("get_", "search_", "find_", "list_")):
197
- return ["query"]
198
- elif command.startswith(("create_", "add_", "insert_")):
199
- return ["mutation", "create"]
200
- elif command.startswith(("update_", "change_", "modify_")):
201
- return ["mutation", "update"]
202
- elif command.startswith(("delete_", "remove_")):
203
- return ["mutation", "delete"]
204
- else:
205
- # Используем первую часть имени команды в качестве тега
206
- parts = command.split("_")
207
- return [parts[0]] if parts else ["other"]
@@ -1,28 +0,0 @@
1
- adapters/__init__.py,sha256=7QraK1j5y29KFSRF4mVxTiWC2Y3IYZLd6GhxUCtjyhg,790
2
- analyzers/__init__.py,sha256=2rcYZDP-bXq078MQpxP32lAwYYyRhOwAQGBcefBfBzY,368
3
- analyzers/docstring_analyzer.py,sha256=T3FLJEo_uChShfiEKRl8GpVoHvh5HiudZkxnj4KixfA,7541
4
- analyzers/type_analyzer.py,sha256=6Wac7osKwF03waFSwQ8ZM0Wqn_zAP2D-I4WMEpR0hQM,5230
5
- cli/__init__.py,sha256=vJ0VTT7D4KRIOi9nQSgBLub7xywq68i2R1zYQkdA0Uk,416
6
- cli/__main__.py,sha256=qtjEOB4vkeMASjTppyRFok4IFihRrVOqjk6vLx8OW1g,2400
7
- cli/command_runner.py,sha256=4d0BZKRG9k4CLk3ZE26jfSxwwrls2e-KsflRoVimfyE,8328
8
- dispatchers/__init__.py,sha256=FWgimgInGphIjCEnvA3-ZExiapUzYAVis2H9C5IWivU,365
9
- dispatchers/base_dispatcher.py,sha256=S5_Xri058jAmOWeit1tedB_GMZQ9RLcNcYabA83ZF6k,2288
10
- dispatchers/json_rpc_dispatcher.py,sha256=ffu1M32E1AdC7IB44mlbV2L56eJQMsp-7fYi_r4rmHc,6331
11
- generators/__init__.py,sha256=KC8p2HcIBqdyCY1wHnN_c1EfbnPM39YhZLNBDcuv3vA,538
12
- generators/endpoint_generator.py,sha256=fhEInY3JPwdc5EENesN9VrrONwVZMpsledVpubouJLA,6513
13
- generators/openapi_generator.py,sha256=0Iqsn0fRr10sTWUK9-MU5MXOXKDHccxKYnmaiQPkKFw,9773
14
- generators/rest_api_generator.py,sha256=Zg9HVeIuspowXd6aBlyho4UXz-te_Hd4egGzjjIVF48,9159
15
- mcp_proxy_adapter-2.1.0.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
16
- openapi_schema/__init__.py,sha256=S_lEg-VtlgDdhFxB_u9ZUM1dWKbzW_L_FM-6OCT4EXM,1334
17
- openapi_schema/command_registry.py,sha256=VqqdsVCcd5neqZ-bsfeKTHeLBeputwUZHxvNxVuvqZs,12075
18
- openapi_schema/rest_schema.py,sha256=nfF9axtmEA-B-Rw8TCnpmRf6Br3MfQ3TJVx-QHUHoy8,24103
19
- openapi_schema/rpc_generator.py,sha256=5FGMqjMXcaW0Ej6oey5mgiIxtEKTtA87dc-_kWLWqb0,13640
20
- openapi_schema/rpc_schema.py,sha256=pebSNt9rKyP2dyHpbjSllak6pQe5AnllReKHhR3UIaI,20162
21
- validators/__init__.py,sha256=s6zd5oZ3V2pXtzONoH3CiZYLzSVtCoLXpETMFUQfwWY,403
22
- validators/base_validator.py,sha256=qTEcXnfGqsgKKtc-lnttLiPTuq6vOHfDpZrQ5oP5Fi0,602
23
- validators/docstring_validator.py,sha256=Onpq2iNJ1qF4ejkJJIlBkLROuSNIVALHVmXIgkCpaFI,2934
24
- validators/metadata_validator.py,sha256=uCrn38-VYYn89l6f5CC_GoTAHAweaOW2Z6Esro1rtGw,3155
25
- mcp_proxy_adapter-2.1.0.dist-info/METADATA,sha256=NzrDAS6Q9E1vrPY-xzm72Uq09hncset_5NrFyIYPDvc,8158
26
- mcp_proxy_adapter-2.1.0.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
27
- mcp_proxy_adapter-2.1.0.dist-info/top_level.txt,sha256=SlVzE4ry_0xTgDmO2uiaI7ihb9MpR62izN4MH_t1BTU,72
28
- mcp_proxy_adapter-2.1.0.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- adapters
2
- analyzers
3
- cli
4
- dispatchers
5
- generators
6
- openapi_schema
7
- validators
@@ -1,38 +0,0 @@
1
- """
2
- Combined OpenAPI schema for REST and RPC API.
3
- Provides the get_openapi_schema function that returns the complete OpenAPI schema.
4
- """
5
- from typing import Dict, Any
6
-
7
- from .rest_schema import get_rest_schema
8
- from .rpc_generator import generate_rpc_schema
9
-
10
- __all__ = ["get_openapi_schema"]
11
-
12
-
13
- def get_openapi_schema() -> Dict[str, Any]:
14
- """
15
- Gets the complete OpenAPI schema that includes both REST and RPC interfaces.
16
-
17
- Returns:
18
- Dict[str, Any]: Complete OpenAPI schema
19
- """
20
- # Get the base REST schema
21
- openapi_schema = get_rest_schema()
22
-
23
- # Generate RPC schema based on REST schema
24
- rpc_schema = generate_rpc_schema(openapi_schema)
25
-
26
- # Add /cmd endpoint from RPC schema to the general schema
27
- openapi_schema["paths"].update(rpc_schema["paths"])
28
-
29
- # Merge schema components
30
- for component_type, components in rpc_schema["components"].items():
31
- if component_type not in openapi_schema["components"]:
32
- openapi_schema["components"][component_type] = {}
33
- for component_name, component in components.items():
34
- # Avoid component duplication
35
- if component_name not in openapi_schema["components"][component_type]:
36
- openapi_schema["components"][component_type][component_name] = component
37
-
38
- return openapi_schema