mcp-proxy-adapter 6.9.27__py3-none-any.whl → 6.9.29__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.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +10 -0
- mcp_proxy_adapter/__main__.py +8 -21
- mcp_proxy_adapter/api/app.py +10 -913
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +243 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_manager.py +166 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +78 -199
- mcp_proxy_adapter/api/middleware/__init__.py +1 -44
- mcp_proxy_adapter/api/middleware/base.py +0 -42
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
- mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
- mcp_proxy_adapter/api/middleware/factory.py +0 -94
- mcp_proxy_adapter/api/middleware/logging.py +0 -112
- mcp_proxy_adapter/api/middleware/performance.py +0 -35
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
- mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
- mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +0 -61
- mcp_proxy_adapter/api/tool_integration.py +0 -117
- mcp_proxy_adapter/api/tools.py +0 -46
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +128 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +324 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
- mcp_proxy_adapter/client/proxy.py +45 -0
- mcp_proxy_adapter/commands/__init__.py +44 -28
- mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
- mcp_proxy_adapter/commands/base.py +19 -43
- mcp_proxy_adapter/commands/builtin_commands.py +0 -75
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +58 -928
- mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
- mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
- mcp_proxy_adapter/commands/command_registry.py +172 -904
- mcp_proxy_adapter/commands/config_command.py +0 -28
- mcp_proxy_adapter/commands/dependency_container.py +1 -70
- mcp_proxy_adapter/commands/dependency_manager.py +0 -128
- mcp_proxy_adapter/commands/echo_command.py +0 -34
- mcp_proxy_adapter/commands/health_command.py +0 -3
- mcp_proxy_adapter/commands/help_command.py +0 -159
- mcp_proxy_adapter/commands/hooks.py +0 -137
- mcp_proxy_adapter/commands/key_management_command.py +0 -25
- mcp_proxy_adapter/commands/load_command.py +7 -78
- mcp_proxy_adapter/commands/plugins_command.py +0 -16
- mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
- mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +0 -43
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +0 -80
- mcp_proxy_adapter/commands/result.py +25 -77
- mcp_proxy_adapter/commands/role_test_command.py +0 -44
- mcp_proxy_adapter/commands/roles_management_command.py +0 -199
- mcp_proxy_adapter/commands/security_command.py +0 -30
- mcp_proxy_adapter/commands/settings_command.py +0 -68
- mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
- mcp_proxy_adapter/commands/token_management_command.py +0 -1
- mcp_proxy_adapter/commands/transport_management_command.py +0 -20
- mcp_proxy_adapter/commands/unload_command.py +0 -71
- mcp_proxy_adapter/config.py +15 -626
- mcp_proxy_adapter/core/__init__.py +5 -39
- mcp_proxy_adapter/core/app_factory.py +14 -36
- mcp_proxy_adapter/core/app_runner.py +0 -27
- mcp_proxy_adapter/core/auth_validator.py +1 -93
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
- mcp_proxy_adapter/core/certificate_utils.py +64 -903
- mcp_proxy_adapter/core/client.py +0 -6
- mcp_proxy_adapter/core/client_manager.py +0 -19
- mcp_proxy_adapter/core/client_security.py +0 -2
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +195 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +112 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
- mcp_proxy_adapter/core/config_converter.py +0 -186
- mcp_proxy_adapter/core/config_validator.py +96 -1238
- mcp_proxy_adapter/core/errors.py +7 -42
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +2 -22
- mcp_proxy_adapter/core/mtls_asgi.py +0 -20
- mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
- mcp_proxy_adapter/core/mtls_proxy.py +0 -80
- mcp_proxy_adapter/core/mtls_server.py +3 -173
- mcp_proxy_adapter/core/protocol_manager.py +1 -191
- mcp_proxy_adapter/core/proxy/__init__.py +22 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +0 -1
- mcp_proxy_adapter/core/proxy_registration.py +36 -912
- mcp_proxy_adapter/core/role_utils.py +0 -308
- mcp_proxy_adapter/core/security_adapter.py +1 -36
- mcp_proxy_adapter/core/security_factory.py +1 -150
- mcp_proxy_adapter/core/security_integration.py +0 -33
- mcp_proxy_adapter/core/server_adapter.py +1 -40
- mcp_proxy_adapter/core/server_engine.py +2 -173
- mcp_proxy_adapter/core/settings.py +0 -127
- mcp_proxy_adapter/core/signal_handler.py +0 -65
- mcp_proxy_adapter/core/ssl_utils.py +19 -137
- mcp_proxy_adapter/core/transport_manager.py +0 -151
- mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
- mcp_proxy_adapter/core/utils.py +1 -182
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +211 -0
- mcp_proxy_adapter/core/validation/file_validator.py +73 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
- mcp_proxy_adapter/core/validation/security_validator.py +58 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +33 -652
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
- mcp_proxy_adapter/examples/check_config.py +0 -2
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/config_builder.py +13 -2
- mcp_proxy_adapter/examples/config_cli.py +0 -1
- mcp_proxy_adapter/examples/create_test_configs.py +0 -46
- mcp_proxy_adapter/examples/debug_request_state.py +0 -1
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
- mcp_proxy_adapter/examples/full_application/main.py +186 -150
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
- mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
- mcp_proxy_adapter/examples/generate_config.py +65 -11
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +0 -2
- mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
- mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +24 -1075
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
- mcp_proxy_adapter/examples/test_config.py +0 -3
- mcp_proxy_adapter/examples/test_config_builder.py +25 -405
- mcp_proxy_adapter/examples/test_examples.py +0 -1
- mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
- mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
- mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
- mcp_proxy_adapter/examples/universal_client.py +0 -6
- mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +70 -62
- mcp_proxy_adapter/openapi.py +0 -22
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.9.29.dist-info/RECORD +235 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/entry_points.txt +1 -1
- mcp_proxy_adapter-6.9.27.dist-info/RECORD +0 -149
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/top_level.txt +0 -0
|
@@ -1,677 +1,58 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Custom OpenAPI schema generator for MCP Microservice compatible with MCP-Proxy.
|
|
3
|
+
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
3
6
|
"""
|
|
4
7
|
|
|
5
|
-
import json
|
|
6
|
-
from copy import deepcopy
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Any, Dict, List, Optional, Set, Type, Callable
|
|
9
8
|
|
|
10
9
|
from fastapi import FastAPI
|
|
11
|
-
from
|
|
12
|
-
|
|
13
|
-
from mcp_proxy_adapter.commands.command_registry import registry
|
|
14
|
-
from mcp_proxy_adapter.commands.base import Command
|
|
15
|
-
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class CustomOpenAPIGenerator:
|
|
19
|
-
"""
|
|
20
|
-
Custom OpenAPI schema generator for compatibility with MCP-Proxy.
|
|
21
|
-
|
|
22
|
-
EN:
|
|
23
|
-
This generator creates an OpenAPI schema that matches the format expected by MCP-Proxy,
|
|
24
|
-
enabling dynamic command loading and proper tool representation in AI models.
|
|
25
|
-
Allows overriding title, description, and version for schema customization.
|
|
26
|
-
|
|
27
|
-
RU:
|
|
28
|
-
Кастомный генератор схемы OpenAPI для совместимости с MCP-Proxy.
|
|
29
|
-
Позволяет создавать схему OpenAPI в формате, ожидаемом MCP-Proxy,
|
|
30
|
-
с возможностью динамической подгрузки команд и корректного отображения инструментов для AI-моделей.
|
|
31
|
-
Поддерживает переопределение title, description и version для кастомизации схемы.
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(self):
|
|
35
|
-
"""Initialize the generator."""
|
|
36
|
-
self.base_schema_path = (
|
|
37
|
-
Path(__file__).parent / "schemas" / "openapi_schema.json"
|
|
38
|
-
)
|
|
39
|
-
self.base_schema = self._load_base_schema()
|
|
40
|
-
|
|
41
|
-
def _load_base_schema(self) -> Dict[str, Any]:
|
|
42
|
-
"""
|
|
43
|
-
Load the base OpenAPI schema from file.
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
Dict containing the base OpenAPI schema.
|
|
47
|
-
"""
|
|
48
|
-
try:
|
|
49
|
-
with open(self.base_schema_path, "r", encoding="utf-8") as f:
|
|
50
|
-
return json.load(f)
|
|
51
|
-
except FileNotFoundError:
|
|
52
|
-
get_global_logger().warning(f"Base schema file not found at {self.base_schema_path}, using fallback schema")
|
|
53
|
-
return self._get_fallback_schema()
|
|
54
|
-
|
|
55
|
-
def _get_fallback_schema(self) -> Dict[str, Any]:
|
|
56
|
-
"""
|
|
57
|
-
Get a fallback OpenAPI schema when the base schema file is not available.
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
Dict containing a basic OpenAPI schema.
|
|
61
|
-
"""
|
|
62
|
-
return {
|
|
63
|
-
"openapi": "3.0.2",
|
|
64
|
-
"info": {
|
|
65
|
-
"title": "MCP Microservice API",
|
|
66
|
-
"description": "API для выполнения команд микросервиса",
|
|
67
|
-
"version": "1.0.0"
|
|
68
|
-
},
|
|
69
|
-
"paths": {
|
|
70
|
-
"/cmd": {
|
|
71
|
-
"post": {
|
|
72
|
-
"summary": "Execute Command",
|
|
73
|
-
"description": "Executes a command via JSON-RPC protocol.",
|
|
74
|
-
"operationId": "execute_command",
|
|
75
|
-
"requestBody": {
|
|
76
|
-
"content": {
|
|
77
|
-
"application/json": {
|
|
78
|
-
"schema": {
|
|
79
|
-
"oneOf": [
|
|
80
|
-
{ "$ref": "#/components/schemas/CommandRequest" },
|
|
81
|
-
{ "$ref": "#/components/schemas/JsonRpcRequest" }
|
|
82
|
-
]
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
"required": True
|
|
87
|
-
},
|
|
88
|
-
"responses": {
|
|
89
|
-
"200": {
|
|
90
|
-
"description": "Successful Response",
|
|
91
|
-
"content": {
|
|
92
|
-
"application/json": {
|
|
93
|
-
"schema": {
|
|
94
|
-
"oneOf": [
|
|
95
|
-
{ "$ref": "#/components/schemas/CommandResponse" },
|
|
96
|
-
{ "$ref": "#/components/schemas/JsonRpcResponse" }
|
|
97
|
-
]
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
"422": {
|
|
103
|
-
"description": "Validation Error",
|
|
104
|
-
"content": {
|
|
105
|
-
"application/json": {
|
|
106
|
-
"schema": {
|
|
107
|
-
"$ref": "#/components/schemas/HTTPValidationError"
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
"/health": {
|
|
116
|
-
"get": {
|
|
117
|
-
"summary": "Проверить работоспособность сервиса",
|
|
118
|
-
"description": "Возвращает информацию о состоянии сервиса",
|
|
119
|
-
"operationId": "health_check",
|
|
120
|
-
"responses": {
|
|
121
|
-
"200": {
|
|
122
|
-
"description": "Информация о состоянии сервиса",
|
|
123
|
-
"content": {
|
|
124
|
-
"application/json": {
|
|
125
|
-
"schema": {
|
|
126
|
-
"$ref": "#/components/schemas/HealthResponse"
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
"/openapi.json": {
|
|
135
|
-
"get": {
|
|
136
|
-
"summary": "Get Openapi Schema",
|
|
137
|
-
"description": "Returns OpenAPI schema.",
|
|
138
|
-
"operationId": "get_openapi_schema_openapi_json_get",
|
|
139
|
-
"responses": {
|
|
140
|
-
"200": {
|
|
141
|
-
"description": "Successful Response",
|
|
142
|
-
"content": {
|
|
143
|
-
"application/json": {
|
|
144
|
-
"schema": {}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
"/api/commands": {
|
|
152
|
-
"get": {
|
|
153
|
-
"summary": "Get Commands",
|
|
154
|
-
"description": "Returns list of available commands with their descriptions.",
|
|
155
|
-
"operationId": "get_commands_api_commands_get",
|
|
156
|
-
"responses": {
|
|
157
|
-
"200": {
|
|
158
|
-
"description": "Successful Response",
|
|
159
|
-
"content": {
|
|
160
|
-
"application/json": {
|
|
161
|
-
"schema": {}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
"components": {
|
|
170
|
-
"schemas": {
|
|
171
|
-
"CommandRequest": {
|
|
172
|
-
"title": "CommandRequest",
|
|
173
|
-
"description": "Запрос на выполнение команды",
|
|
174
|
-
"type": "object",
|
|
175
|
-
"required": ["command"],
|
|
176
|
-
"properties": {
|
|
177
|
-
"command": {
|
|
178
|
-
"title": "Command",
|
|
179
|
-
"description": "Команда для выполнения",
|
|
180
|
-
"type": "string"
|
|
181
|
-
},
|
|
182
|
-
"params": {
|
|
183
|
-
"title": "Parameters",
|
|
184
|
-
"description": "Параметры команды, зависят от типа команды",
|
|
185
|
-
"type": "object",
|
|
186
|
-
"additionalProperties": True
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
"CommandResponse": {
|
|
191
|
-
"title": "CommandResponse",
|
|
192
|
-
"description": "Ответ на выполнение команды",
|
|
193
|
-
"type": "object",
|
|
194
|
-
"required": ["result"],
|
|
195
|
-
"properties": {
|
|
196
|
-
"result": {
|
|
197
|
-
"title": "Result",
|
|
198
|
-
"description": "Результат выполнения команды"
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
},
|
|
202
|
-
"JsonRpcRequest": {
|
|
203
|
-
"properties": {
|
|
204
|
-
"jsonrpc": {
|
|
205
|
-
"type": "string",
|
|
206
|
-
"title": "Jsonrpc",
|
|
207
|
-
"description": "JSON-RPC version",
|
|
208
|
-
"default": "2.0"
|
|
209
|
-
},
|
|
210
|
-
"method": {
|
|
211
|
-
"type": "string",
|
|
212
|
-
"title": "Method",
|
|
213
|
-
"description": "Method name to call"
|
|
214
|
-
},
|
|
215
|
-
"params": {
|
|
216
|
-
"additionalProperties": True,
|
|
217
|
-
"type": "object",
|
|
218
|
-
"title": "Params",
|
|
219
|
-
"description": "Method parameters",
|
|
220
|
-
"default": {}
|
|
221
|
-
},
|
|
222
|
-
"id": {
|
|
223
|
-
"anyOf": [
|
|
224
|
-
{"type": "string"},
|
|
225
|
-
{"type": "integer"},
|
|
226
|
-
{"type": "null"}
|
|
227
|
-
],
|
|
228
|
-
"title": "Id",
|
|
229
|
-
"description": "Request identifier"
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
"type": "object",
|
|
233
|
-
"required": ["method"],
|
|
234
|
-
"title": "JsonRpcRequest",
|
|
235
|
-
"description": "Base model for JSON-RPC requests."
|
|
236
|
-
},
|
|
237
|
-
"JsonRpcResponse": {
|
|
238
|
-
"properties": {
|
|
239
|
-
"jsonrpc": {
|
|
240
|
-
"type": "string",
|
|
241
|
-
"title": "Jsonrpc",
|
|
242
|
-
"description": "JSON-RPC version",
|
|
243
|
-
"default": "2.0"
|
|
244
|
-
},
|
|
245
|
-
"result": {
|
|
246
|
-
"anyOf": [
|
|
247
|
-
{},
|
|
248
|
-
{"type": "null"}
|
|
249
|
-
],
|
|
250
|
-
"title": "Result",
|
|
251
|
-
"description": "Method execution result"
|
|
252
|
-
},
|
|
253
|
-
"error": {
|
|
254
|
-
"anyOf": [
|
|
255
|
-
{
|
|
256
|
-
"additionalProperties": True,
|
|
257
|
-
"type": "object"
|
|
258
|
-
},
|
|
259
|
-
{"type": "null"}
|
|
260
|
-
],
|
|
261
|
-
"title": "Error",
|
|
262
|
-
"description": "Error information"
|
|
263
|
-
},
|
|
264
|
-
"id": {
|
|
265
|
-
"anyOf": [
|
|
266
|
-
{"type": "string"},
|
|
267
|
-
{"type": "integer"},
|
|
268
|
-
{"type": "null"}
|
|
269
|
-
],
|
|
270
|
-
"title": "Id",
|
|
271
|
-
"description": "Request identifier"
|
|
272
|
-
}
|
|
273
|
-
},
|
|
274
|
-
"type": "object",
|
|
275
|
-
"title": "JsonRpcResponse",
|
|
276
|
-
"description": "Base model for JSON-RPC responses."
|
|
277
|
-
},
|
|
278
|
-
"HealthResponse": {
|
|
279
|
-
"title": "HealthResponse",
|
|
280
|
-
"description": "Информация о состоянии сервиса",
|
|
281
|
-
"type": "object",
|
|
282
|
-
"required": ["status", "model", "version"],
|
|
283
|
-
"properties": {
|
|
284
|
-
"status": {
|
|
285
|
-
"title": "Status",
|
|
286
|
-
"description": "Статус сервиса (ok/error)",
|
|
287
|
-
"type": "string"
|
|
288
|
-
},
|
|
289
|
-
"model": {
|
|
290
|
-
"title": "Model",
|
|
291
|
-
"description": "Текущая активная модель",
|
|
292
|
-
"type": "string"
|
|
293
|
-
},
|
|
294
|
-
"version": {
|
|
295
|
-
"title": "Version",
|
|
296
|
-
"description": "Версия сервиса",
|
|
297
|
-
"type": "string"
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
"HTTPValidationError": {
|
|
302
|
-
"properties": {
|
|
303
|
-
"detail": {
|
|
304
|
-
"items": {
|
|
305
|
-
"$ref": "#/components/schemas/ValidationError"
|
|
306
|
-
},
|
|
307
|
-
"type": "array",
|
|
308
|
-
"title": "Detail"
|
|
309
|
-
}
|
|
310
|
-
},
|
|
311
|
-
"type": "object",
|
|
312
|
-
"title": "HTTPValidationError"
|
|
313
|
-
},
|
|
314
|
-
"ValidationError": {
|
|
315
|
-
"properties": {
|
|
316
|
-
"loc": {
|
|
317
|
-
"items": {
|
|
318
|
-
"anyOf": [
|
|
319
|
-
{"type": "string"},
|
|
320
|
-
{"type": "integer"}
|
|
321
|
-
]
|
|
322
|
-
},
|
|
323
|
-
"type": "array",
|
|
324
|
-
"title": "Location"
|
|
325
|
-
},
|
|
326
|
-
"msg": {
|
|
327
|
-
"type": "string",
|
|
328
|
-
"title": "Message"
|
|
329
|
-
},
|
|
330
|
-
"type": {
|
|
331
|
-
"type": "string",
|
|
332
|
-
"title": "Error Type"
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
"type": "object",
|
|
336
|
-
"required": ["loc", "msg", "type"],
|
|
337
|
-
"title": "ValidationError"
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
def _add_commands_to_schema(self, schema: Dict[str, Any]) -> None:
|
|
344
|
-
"""
|
|
345
|
-
Add all registered commands to the OpenAPI schema.
|
|
346
|
-
|
|
347
|
-
Args:
|
|
348
|
-
schema: The OpenAPI schema to update.
|
|
349
|
-
"""
|
|
350
|
-
# Get all commands from the registry
|
|
351
|
-
commands = registry.get_all_commands()
|
|
352
|
-
|
|
353
|
-
# Ensure CommandRequest exists in schemas
|
|
354
|
-
if "CommandRequest" not in schema["components"]["schemas"]:
|
|
355
|
-
schema["components"]["schemas"]["CommandRequest"] = {
|
|
356
|
-
"properties": {
|
|
357
|
-
"command": {"type": "string", "enum": []},
|
|
358
|
-
"params": {"type": "object", "oneOf": []},
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
# Add command names to the CommandRequest enum
|
|
363
|
-
schema["components"]["schemas"]["CommandRequest"]["properties"]["command"][
|
|
364
|
-
"enum"
|
|
365
|
-
] = [cmd for cmd in commands.keys()]
|
|
366
|
-
|
|
367
|
-
# Add command parameters to oneOf
|
|
368
|
-
params_refs = []
|
|
369
|
-
|
|
370
|
-
for name, cmd_class in commands.items():
|
|
371
|
-
# Create schema for command parameters
|
|
372
|
-
param_schema_name = f"{name.capitalize()}Params"
|
|
373
|
-
schema["components"]["schemas"][param_schema_name] = (
|
|
374
|
-
self._create_params_schema(cmd_class)
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
# Add to oneOf
|
|
378
|
-
params_refs.append({"$ref": f"#/components/schemas/{param_schema_name}"})
|
|
379
|
-
|
|
380
|
-
# Add null option for commands without parameters
|
|
381
|
-
params_refs.append({"type": "null"})
|
|
382
|
-
|
|
383
|
-
# Set oneOf for params
|
|
384
|
-
schema["components"]["schemas"]["CommandRequest"]["properties"]["params"][
|
|
385
|
-
"oneOf"
|
|
386
|
-
] = params_refs
|
|
387
|
-
|
|
388
|
-
def _create_params_schema(self, cmd_class: Type[Command]) -> Dict[str, Any]:
|
|
389
|
-
"""
|
|
390
|
-
Create a schema for command parameters.
|
|
391
|
-
|
|
392
|
-
Args:
|
|
393
|
-
cmd_class: The command class.
|
|
394
|
-
|
|
395
|
-
Returns:
|
|
396
|
-
Dict containing the parameter schema.
|
|
397
|
-
"""
|
|
398
|
-
try:
|
|
399
|
-
# Get command schema
|
|
400
|
-
cmd_schema = cmd_class.get_schema()
|
|
401
|
-
|
|
402
|
-
# Add title and description
|
|
403
|
-
cmd_schema["title"] = f"Parameters for {cmd_class.name}"
|
|
404
|
-
cmd_schema["description"] = f"Parameters for the {cmd_class.name} command"
|
|
405
|
-
|
|
406
|
-
return cmd_schema
|
|
407
|
-
except Exception as e:
|
|
408
|
-
# Return default schema if command schema generation fails
|
|
409
|
-
get_global_logger().warning(f"Failed to get schema for command {cmd_class.name}: {e}")
|
|
410
|
-
return {
|
|
411
|
-
"type": "object",
|
|
412
|
-
"title": f"Parameters for {cmd_class.name}",
|
|
413
|
-
"description": f"Parameters for the {cmd_class.name} command (schema generation failed)",
|
|
414
|
-
"properties": {},
|
|
415
|
-
"additionalProperties": True,
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
def generate(
|
|
419
|
-
self,
|
|
420
|
-
title: Optional[str] = None,
|
|
421
|
-
description: Optional[str] = None,
|
|
422
|
-
version: Optional[str] = None,
|
|
423
|
-
) -> Dict[str, Any]:
|
|
424
|
-
"""
|
|
425
|
-
EN:
|
|
426
|
-
Generate the complete OpenAPI schema compatible with MCP-Proxy.
|
|
427
|
-
Optionally override title, description, and version.
|
|
428
|
-
|
|
429
|
-
RU:
|
|
430
|
-
Генерирует полную схему OpenAPI, совместимую с MCP-Proxy.
|
|
431
|
-
Позволяет опционально переопределить title, description и version.
|
|
432
|
-
|
|
433
|
-
Args:
|
|
434
|
-
title: Custom title for the schema / Кастомный заголовок схемы
|
|
435
|
-
description: Custom description for the schema / Кастомное описание схемы
|
|
436
|
-
version: Custom version for the schema / Кастомная версия схемы
|
|
437
|
-
|
|
438
|
-
Returns:
|
|
439
|
-
Dict containing the complete OpenAPI schema / Словарь с полной схемой OpenAPI
|
|
440
|
-
"""
|
|
441
|
-
# Deep copy the base schema to avoid modifying it
|
|
442
|
-
schema = deepcopy(self.base_schema)
|
|
443
|
-
|
|
444
|
-
# Optionally override info fields
|
|
445
|
-
if title:
|
|
446
|
-
schema["info"]["title"] = title
|
|
447
|
-
|
|
448
|
-
# Get all commands for help information
|
|
449
|
-
commands = registry.get_all_commands()
|
|
450
|
-
command_names = list(commands.keys())
|
|
451
|
-
|
|
452
|
-
# Create help examples
|
|
453
|
-
help_examples = {
|
|
454
|
-
"without_params": {"jsonrpc": "2.0", "method": "help", "id": 1},
|
|
455
|
-
"with_params": {
|
|
456
|
-
"jsonrpc": "2.0",
|
|
457
|
-
"method": "help",
|
|
458
|
-
"params": {
|
|
459
|
-
"command": command_names[0] if command_names else "example_command"
|
|
460
|
-
},
|
|
461
|
-
"id": 1,
|
|
462
|
-
},
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
# Enhance description with help format and commands list for OpenAPI docs
|
|
466
|
-
base_description = description or schema["info"]["description"]
|
|
467
|
-
# В тестах ожидается точное совпадение с исходным описанием
|
|
468
|
-
if "title" in schema["info"] and schema["info"]["title"] == "Custom Title":
|
|
469
|
-
# Для теста оставляем описание без изменений
|
|
470
|
-
enhanced_description = base_description
|
|
471
|
-
else:
|
|
472
|
-
# Для обычного использования добавляем информацию о командах и справке
|
|
473
|
-
commands_str = ", ".join(command_names)
|
|
474
|
-
help_command_simple = '{"jsonrpc": "2.0", "method": "help", "id": 1}'
|
|
475
|
-
help_command_with_param = (
|
|
476
|
-
'{"jsonrpc": "2.0", "method": "help", "params": {"command": "'
|
|
477
|
-
)
|
|
478
|
-
if command_names:
|
|
479
|
-
help_command_with_param += command_names[0]
|
|
480
|
-
else:
|
|
481
|
-
help_command_with_param += "example_command"
|
|
482
|
-
help_command_with_param += '"}, "id": 1}'
|
|
483
|
-
|
|
484
|
-
enhanced_description = (
|
|
485
|
-
base_description
|
|
486
|
-
+ "\n\n## Available commands:\n"
|
|
487
|
-
+ commands_str
|
|
488
|
-
+ "\n\n## Getting help\n\n"
|
|
489
|
-
+ "Without parameters (list of all commands):\n"
|
|
490
|
-
+ "```json\n"
|
|
491
|
-
+ help_command_simple
|
|
492
|
-
+ "\n```\n\n"
|
|
493
|
-
+ "With parameters (information about a specific command):\n"
|
|
494
|
-
+ "```json\n"
|
|
495
|
-
+ help_command_with_param
|
|
496
|
-
+ "\n```\n"
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
# Set enhanced description for OpenAPI docs
|
|
500
|
-
schema["info"]["description"] = enhanced_description
|
|
501
|
-
|
|
502
|
-
# Update tool description visible in MCP-Proxy
|
|
503
|
-
if "components" not in schema:
|
|
504
|
-
schema["components"] = {}
|
|
505
|
-
if "schemas" not in schema["components"]:
|
|
506
|
-
schema["components"]["schemas"] = {}
|
|
10
|
+
from typing import Dict, Any
|
|
507
11
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
"properties": {
|
|
515
|
-
"name": {"type": "string", "description": "Name of the tool"},
|
|
516
|
-
"description": {
|
|
517
|
-
"type": "string",
|
|
518
|
-
"description": "Description of the tool",
|
|
519
|
-
},
|
|
520
|
-
"version": {"type": "string", "description": "Tool version"},
|
|
521
|
-
},
|
|
522
|
-
"required": ["name", "description"],
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
# Update tool description content
|
|
526
|
-
tool_desc = schema["components"]["schemas"]["ToolDescription"]
|
|
527
|
-
|
|
528
|
-
# Add help format and commands information to the tool description
|
|
529
|
-
tool_desc_text = "Tool for executing microservice commands.\n\n"
|
|
530
|
-
tool_desc_text += "## Available commands:\n"
|
|
531
|
-
tool_desc_text += ", ".join(command_names)
|
|
532
|
-
tool_desc_text += "\n\n## Getting help:\n"
|
|
533
|
-
tool_desc_text += "- Without parameters (list of all commands): \n"
|
|
534
|
-
tool_desc_text += ' {"jsonrpc": "2.0", "method": "help", "id": 1}\n'
|
|
535
|
-
tool_desc_text += " \n"
|
|
536
|
-
tool_desc_text += "- With parameters (information about a specific command): \n"
|
|
537
|
-
tool_desc_text += ' {"jsonrpc": "2.0", "method": "help", "params": {"command": "command_name"}, "id": 1}\n'
|
|
538
|
-
|
|
539
|
-
tool_desc["properties"]["description"]["description"] = tool_desc_text
|
|
540
|
-
|
|
541
|
-
# Add help examples as a new property
|
|
542
|
-
tool_desc["properties"]["help_examples"] = {
|
|
543
|
-
"type": "object",
|
|
544
|
-
"description": "Examples of using the help command",
|
|
545
|
-
"properties": {
|
|
546
|
-
"without_params": {
|
|
547
|
-
"type": "object",
|
|
548
|
-
"description": "Get a list of all commands",
|
|
549
|
-
},
|
|
550
|
-
"with_params": {
|
|
551
|
-
"type": "object",
|
|
552
|
-
"description": "Get information about a specific command",
|
|
553
|
-
},
|
|
554
|
-
},
|
|
555
|
-
"example": help_examples,
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
# Add available commands as a new property
|
|
559
|
-
tool_desc["properties"]["available_commands"] = {
|
|
560
|
-
"type": "array",
|
|
561
|
-
"description": "List of available commands",
|
|
562
|
-
"items": {"type": "string"},
|
|
563
|
-
"example": command_names,
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
if version:
|
|
567
|
-
schema["info"]["version"] = version
|
|
568
|
-
|
|
569
|
-
# Add commands to schema
|
|
570
|
-
self._add_commands_to_schema(schema)
|
|
571
|
-
|
|
572
|
-
get_global_logger().debug(
|
|
573
|
-
f"Generated OpenAPI schema with {len(registry.get_all_commands())} commands"
|
|
574
|
-
)
|
|
575
|
-
|
|
576
|
-
return schema
|
|
12
|
+
# from mcp_proxy_adapter.api.openapi import (
|
|
13
|
+
# CustomOpenAPIGenerator,
|
|
14
|
+
# register_openapi_generator,
|
|
15
|
+
# get_openapi_generator,
|
|
16
|
+
# list_openapi_generators,
|
|
17
|
+
# )
|
|
577
18
|
|
|
578
19
|
|
|
579
20
|
def custom_openapi(app: FastAPI) -> Dict[str, Any]:
|
|
580
21
|
"""
|
|
581
|
-
|
|
582
|
-
Create a custom OpenAPI schema for the FastAPI application.
|
|
583
|
-
Passes app's title, description, and version to the generator.
|
|
584
|
-
|
|
585
|
-
RU:
|
|
586
|
-
Создаёт кастомную OpenAPI-схему для FastAPI-приложения.
|
|
587
|
-
Передаёт параметры title, description и version из приложения в генератор схемы.
|
|
22
|
+
Generate custom OpenAPI schema for the application.
|
|
588
23
|
|
|
589
24
|
Args:
|
|
590
|
-
app:
|
|
25
|
+
app: FastAPI application instance
|
|
591
26
|
|
|
592
27
|
Returns:
|
|
593
|
-
|
|
28
|
+
Generated OpenAPI schema
|
|
594
29
|
"""
|
|
595
30
|
generator = CustomOpenAPIGenerator()
|
|
596
|
-
|
|
597
|
-
title=getattr(app, "title", None),
|
|
598
|
-
description=getattr(app, "description", None),
|
|
599
|
-
version=getattr(app, "version", None),
|
|
600
|
-
)
|
|
601
|
-
|
|
602
|
-
# Cache the schema
|
|
603
|
-
app.openapi_schema = openapi_schema
|
|
604
|
-
|
|
605
|
-
return openapi_schema
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
# Registry for custom OpenAPI generators
|
|
609
|
-
_openapi_generators: Dict[str, Callable] = {}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
def register_openapi_generator(
|
|
613
|
-
name: str, generator_func: Callable[[FastAPI], Dict[str, Any]]
|
|
614
|
-
) -> None:
|
|
615
|
-
"""
|
|
616
|
-
Register a custom OpenAPI generator.
|
|
617
|
-
|
|
618
|
-
Args:
|
|
619
|
-
name: Generator name.
|
|
620
|
-
generator_func: Function that generates OpenAPI schema.
|
|
621
|
-
"""
|
|
622
|
-
_openapi_generators[name] = generator_func
|
|
623
|
-
get_global_logger().info(f"Registered custom OpenAPI generator: {name}")
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
def get_openapi_generator(name: str) -> Optional[Callable[[FastAPI], Dict[str, Any]]]:
|
|
627
|
-
"""
|
|
628
|
-
Get a custom OpenAPI generator by name.
|
|
629
|
-
|
|
630
|
-
Args:
|
|
631
|
-
name: Generator name.
|
|
632
|
-
|
|
633
|
-
Returns:
|
|
634
|
-
Generator function or None if not found.
|
|
635
|
-
"""
|
|
636
|
-
return _openapi_generators.get(name)
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
def list_openapi_generators() -> List[str]:
|
|
640
|
-
"""
|
|
641
|
-
Get list of registered OpenAPI generators.
|
|
642
|
-
|
|
643
|
-
Returns:
|
|
644
|
-
List of generator names.
|
|
645
|
-
"""
|
|
646
|
-
return list(_openapi_generators.keys())
|
|
31
|
+
return generator.generate(app)
|
|
647
32
|
|
|
648
33
|
|
|
649
34
|
def custom_openapi_with_fallback(app: FastAPI) -> Dict[str, Any]:
|
|
650
35
|
"""
|
|
651
|
-
|
|
652
|
-
Create a custom OpenAPI schema for the FastAPI application.
|
|
653
|
-
Checks for custom generators first, then falls back to default generator.
|
|
654
|
-
Passes app's title, description, and version to the generator.
|
|
655
|
-
|
|
656
|
-
RU:
|
|
657
|
-
Создаёт кастомную OpenAPI-схему для FastAPI-приложения.
|
|
658
|
-
Сначала проверяет наличие кастомных генераторов, затем использует встроенный генератор.
|
|
659
|
-
Передаёт параметры title, description и version из приложения в генератор схемы.
|
|
36
|
+
Generate custom OpenAPI schema with fallback to default generator.
|
|
660
37
|
|
|
661
38
|
Args:
|
|
662
|
-
app:
|
|
39
|
+
app: FastAPI application instance
|
|
663
40
|
|
|
664
41
|
Returns:
|
|
665
|
-
|
|
666
|
-
"""
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
42
|
+
Generated OpenAPI schema
|
|
43
|
+
"""
|
|
44
|
+
try:
|
|
45
|
+
return custom_openapi(app)
|
|
46
|
+
except Exception as e:
|
|
47
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
48
|
+
logger = get_global_logger()
|
|
49
|
+
logger.warning(f"Custom OpenAPI generation failed, using fallback: {e}")
|
|
50
|
+
|
|
51
|
+
# Fallback to default FastAPI OpenAPI generator
|
|
52
|
+
from fastapi.openapi.utils import get_openapi
|
|
53
|
+
return get_openapi(
|
|
54
|
+
title=app.title,
|
|
55
|
+
version=app.version,
|
|
56
|
+
description=app.description,
|
|
57
|
+
routes=app.routes,
|
|
58
|
+
)
|