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.

Files changed (212) hide show
  1. mcp_proxy_adapter/__init__.py +10 -0
  2. mcp_proxy_adapter/__main__.py +8 -21
  3. mcp_proxy_adapter/api/app.py +10 -913
  4. mcp_proxy_adapter/api/core/__init__.py +18 -0
  5. mcp_proxy_adapter/api/core/app_factory.py +243 -0
  6. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  7. mcp_proxy_adapter/api/core/registration_manager.py +166 -0
  8. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  9. mcp_proxy_adapter/api/handlers.py +78 -199
  10. mcp_proxy_adapter/api/middleware/__init__.py +1 -44
  11. mcp_proxy_adapter/api/middleware/base.py +0 -42
  12. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
  13. mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
  14. mcp_proxy_adapter/api/middleware/factory.py +0 -94
  15. mcp_proxy_adapter/api/middleware/logging.py +0 -112
  16. mcp_proxy_adapter/api/middleware/performance.py +0 -35
  17. mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
  18. mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
  19. mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
  20. mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
  21. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  22. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  23. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  24. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  25. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  26. mcp_proxy_adapter/api/schemas.py +0 -61
  27. mcp_proxy_adapter/api/tool_integration.py +0 -117
  28. mcp_proxy_adapter/api/tools.py +0 -46
  29. mcp_proxy_adapter/cli/__init__.py +12 -0
  30. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  31. mcp_proxy_adapter/cli/commands/client.py +100 -0
  32. mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
  33. mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
  34. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  35. mcp_proxy_adapter/cli/commands/server.py +174 -0
  36. mcp_proxy_adapter/cli/commands/sets.py +128 -0
  37. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  38. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  39. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  40. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  41. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  42. mcp_proxy_adapter/cli/main.py +63 -0
  43. mcp_proxy_adapter/cli/parser.py +324 -0
  44. mcp_proxy_adapter/cli/validators.py +231 -0
  45. mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
  46. mcp_proxy_adapter/client/proxy.py +45 -0
  47. mcp_proxy_adapter/commands/__init__.py +44 -28
  48. mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
  49. mcp_proxy_adapter/commands/base.py +19 -43
  50. mcp_proxy_adapter/commands/builtin_commands.py +0 -75
  51. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  52. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  53. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  54. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  55. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  56. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  57. mcp_proxy_adapter/commands/catalog_manager.py +58 -928
  58. mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
  59. mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
  60. mcp_proxy_adapter/commands/command_registry.py +172 -904
  61. mcp_proxy_adapter/commands/config_command.py +0 -28
  62. mcp_proxy_adapter/commands/dependency_container.py +1 -70
  63. mcp_proxy_adapter/commands/dependency_manager.py +0 -128
  64. mcp_proxy_adapter/commands/echo_command.py +0 -34
  65. mcp_proxy_adapter/commands/health_command.py +0 -3
  66. mcp_proxy_adapter/commands/help_command.py +0 -159
  67. mcp_proxy_adapter/commands/hooks.py +0 -137
  68. mcp_proxy_adapter/commands/key_management_command.py +0 -25
  69. mcp_proxy_adapter/commands/load_command.py +7 -78
  70. mcp_proxy_adapter/commands/plugins_command.py +0 -16
  71. mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
  72. mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
  73. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  74. mcp_proxy_adapter/commands/registration_status_command.py +0 -43
  75. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  76. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  77. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  78. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  79. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  80. mcp_proxy_adapter/commands/reload_command.py +0 -80
  81. mcp_proxy_adapter/commands/result.py +25 -77
  82. mcp_proxy_adapter/commands/role_test_command.py +0 -44
  83. mcp_proxy_adapter/commands/roles_management_command.py +0 -199
  84. mcp_proxy_adapter/commands/security_command.py +0 -30
  85. mcp_proxy_adapter/commands/settings_command.py +0 -68
  86. mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
  87. mcp_proxy_adapter/commands/token_management_command.py +0 -1
  88. mcp_proxy_adapter/commands/transport_management_command.py +0 -20
  89. mcp_proxy_adapter/commands/unload_command.py +0 -71
  90. mcp_proxy_adapter/config.py +15 -626
  91. mcp_proxy_adapter/core/__init__.py +5 -39
  92. mcp_proxy_adapter/core/app_factory.py +14 -36
  93. mcp_proxy_adapter/core/app_runner.py +0 -27
  94. mcp_proxy_adapter/core/auth_validator.py +1 -93
  95. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  96. mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
  97. mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
  98. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  99. mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
  100. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
  101. mcp_proxy_adapter/core/certificate_utils.py +64 -903
  102. mcp_proxy_adapter/core/client.py +0 -6
  103. mcp_proxy_adapter/core/client_manager.py +0 -19
  104. mcp_proxy_adapter/core/client_security.py +0 -2
  105. mcp_proxy_adapter/core/config/__init__.py +18 -0
  106. mcp_proxy_adapter/core/config/config.py +195 -0
  107. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  108. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  109. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  110. mcp_proxy_adapter/core/config/simple_config.py +112 -0
  111. mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
  112. mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
  113. mcp_proxy_adapter/core/config_converter.py +0 -186
  114. mcp_proxy_adapter/core/config_validator.py +96 -1238
  115. mcp_proxy_adapter/core/errors.py +7 -42
  116. mcp_proxy_adapter/core/job_manager.py +54 -0
  117. mcp_proxy_adapter/core/logging.py +2 -22
  118. mcp_proxy_adapter/core/mtls_asgi.py +0 -20
  119. mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
  120. mcp_proxy_adapter/core/mtls_proxy.py +0 -80
  121. mcp_proxy_adapter/core/mtls_server.py +3 -173
  122. mcp_proxy_adapter/core/protocol_manager.py +1 -191
  123. mcp_proxy_adapter/core/proxy/__init__.py +22 -0
  124. mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
  125. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
  126. mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
  127. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  128. mcp_proxy_adapter/core/proxy_client.py +0 -1
  129. mcp_proxy_adapter/core/proxy_registration.py +36 -912
  130. mcp_proxy_adapter/core/role_utils.py +0 -308
  131. mcp_proxy_adapter/core/security_adapter.py +1 -36
  132. mcp_proxy_adapter/core/security_factory.py +1 -150
  133. mcp_proxy_adapter/core/security_integration.py +0 -33
  134. mcp_proxy_adapter/core/server_adapter.py +1 -40
  135. mcp_proxy_adapter/core/server_engine.py +2 -173
  136. mcp_proxy_adapter/core/settings.py +0 -127
  137. mcp_proxy_adapter/core/signal_handler.py +0 -65
  138. mcp_proxy_adapter/core/ssl_utils.py +19 -137
  139. mcp_proxy_adapter/core/transport_manager.py +0 -151
  140. mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
  141. mcp_proxy_adapter/core/utils.py +1 -182
  142. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  143. mcp_proxy_adapter/core/validation/config_validator.py +211 -0
  144. mcp_proxy_adapter/core/validation/file_validator.py +73 -0
  145. mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
  146. mcp_proxy_adapter/core/validation/security_validator.py +58 -0
  147. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  148. mcp_proxy_adapter/custom_openapi.py +33 -652
  149. mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
  150. mcp_proxy_adapter/examples/check_config.py +0 -2
  151. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  152. mcp_proxy_adapter/examples/config_builder.py +13 -2
  153. mcp_proxy_adapter/examples/config_cli.py +0 -1
  154. mcp_proxy_adapter/examples/create_test_configs.py +0 -46
  155. mcp_proxy_adapter/examples/debug_request_state.py +0 -1
  156. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
  157. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
  158. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
  159. mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
  160. mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
  161. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
  162. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
  163. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
  164. mcp_proxy_adapter/examples/full_application/main.py +186 -150
  165. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
  166. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
  167. mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
  168. mcp_proxy_adapter/examples/generate_config.py +65 -11
  169. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  170. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  171. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  172. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  173. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  174. mcp_proxy_adapter/examples/required_certificates.py +0 -2
  175. mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
  176. mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
  177. mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
  178. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  179. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  180. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  181. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  182. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  183. mcp_proxy_adapter/examples/security_test_client.py +24 -1075
  184. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  185. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  186. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  187. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  188. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  189. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  190. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  191. mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
  192. mcp_proxy_adapter/examples/test_config.py +0 -3
  193. mcp_proxy_adapter/examples/test_config_builder.py +25 -405
  194. mcp_proxy_adapter/examples/test_examples.py +0 -1
  195. mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
  196. mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
  197. mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
  198. mcp_proxy_adapter/examples/universal_client.py +0 -6
  199. mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
  200. mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
  201. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
  202. mcp_proxy_adapter/integrations/__init__.py +25 -0
  203. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  204. mcp_proxy_adapter/main.py +70 -62
  205. mcp_proxy_adapter/openapi.py +0 -22
  206. mcp_proxy_adapter/version.py +1 -1
  207. {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/METADATA +2 -1
  208. mcp_proxy_adapter-6.9.29.dist-info/RECORD +235 -0
  209. {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/entry_points.txt +1 -1
  210. mcp_proxy_adapter-6.9.27.dist-info/RECORD +0 -149
  211. {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/WHEEL +0 -0
  212. {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/top_level.txt +0 -0
@@ -130,121 +130,3 @@ class UserInfoMiddleware(BaseHTTPMiddleware):
130
130
  else:
131
131
  get_global_logger().info("ℹ️ User info middleware initialized with mcp_security_framework (fallback enabled)")
132
132
 
133
- async def dispatch(
134
- self, request: Request, call_next: Callable[[Request], Awaitable[Response]]
135
- ) -> Response:
136
- """
137
- Process request and set user info in request.state.
138
-
139
- Args:
140
- request: Request object
141
- call_next: Next handler
142
-
143
- Returns:
144
- Response object
145
- """
146
- get_global_logger().debug(f"🔍 UserInfoMiddleware.dispatch START - {request.method} {request.url.path}")
147
- get_global_logger().debug(f"🔍 UserInfoMiddleware - Headers: {dict(request.headers)}")
148
- get_global_logger().debug(f"🔍 UserInfoMiddleware - AuthManager available: {self.auth_manager is not None}")
149
- get_global_logger().debug(f"🔍 UserInfoMiddleware - Security available: {self._security_available}")
150
-
151
- # Extract API key from headers
152
- api_key = request.headers.get("X-API-Key")
153
- get_global_logger().debug(f"🔍 UserInfoMiddleware - API Key: {api_key[:8] + '...' if api_key else 'None'}")
154
- if api_key:
155
- if self.auth_manager and self._security_available:
156
- try:
157
- # Use mcp_security_framework AuthManager
158
- auth_result = self.auth_manager.authenticate_api_key(api_key)
159
-
160
- if auth_result.is_valid:
161
- # Set user info from AuthManager result
162
- request.state.user = {
163
- "id": api_key,
164
- "role": (
165
- auth_result.roles[0] if auth_result.roles else "guest"
166
- ),
167
- "roles": auth_result.roles or ["guest"],
168
- "permissions": getattr(
169
- auth_result, "permissions", ["read"]
170
- ),
171
- }
172
- get_global_logger().debug(
173
- f"✅ Authenticated user with "
174
- f"mcp_security_framework: "
175
- f"{request.state.user}"
176
- )
177
- else:
178
- # Authentication failed
179
- request.state.user = {
180
- "id": None,
181
- "role": "guest",
182
- "roles": ["guest"],
183
- "permissions": ["read"],
184
- }
185
- get_global_logger().debug(
186
- f"❌ Authentication failed for API key: "
187
- f"{api_key[:8]}..."
188
- )
189
- except Exception as e:
190
- get_global_logger().warning(
191
- f"⚠️ AuthManager error: {e}, " f"falling back to basic auth"
192
- )
193
- self._security_available = False
194
-
195
- if not self._security_available:
196
- # Fallback to basic API key handling
197
- api_keys_dict = getattr(self, "api_keys", {})
198
- # Find role by API key value (not key)
199
- user_role = None
200
- for role, key_value in api_keys_dict.items():
201
- if key_value == api_key:
202
- user_role = role
203
- break
204
-
205
- if user_role:
206
- # Get permissions for this role from roles file if available
207
- role_permissions = ["read"] # default permissions
208
- if (
209
- hasattr(self, "roles_config")
210
- and self.roles_config
211
- and user_role in self.roles_config
212
- ):
213
- role_permissions = self.roles_config[user_role].get(
214
- "permissions", ["read"]
215
- )
216
-
217
- # Set user info in request.state
218
- request.state.user = {
219
- "id": api_key,
220
- "role": user_role,
221
- "roles": [user_role],
222
- "permissions": role_permissions,
223
- }
224
- get_global_logger().debug(
225
- f"✅ User authenticated with API key: "
226
- f"{api_key[:8]}..."
227
- )
228
- else:
229
- # API key not found
230
- request.state.user = {
231
- "id": None,
232
- "role": "guest",
233
- "roles": ["guest"],
234
- "permissions": ["read"],
235
- }
236
- get_global_logger().debug(f"❌ API key not found: {api_key[:8]}...")
237
- else:
238
- # No API key provided - guest access
239
- request.state.user = {
240
- "id": None,
241
- "role": "guest",
242
- "roles": ["guest"],
243
- "permissions": ["read"],
244
- }
245
- get_global_logger().debug("ℹ️ No API key provided, using guest access")
246
-
247
- get_global_logger().debug(f"🔍 UserInfoMiddleware - About to call next handler")
248
- response = await call_next(request)
249
- get_global_logger().debug(f"🔍 UserInfoMiddleware - Next handler completed with status: {response.status_code}")
250
- return response
@@ -0,0 +1,21 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ OpenAPI schema generation package for MCP Proxy Adapter.
6
+ """
7
+
8
+ from .openapi_generator import CustomOpenAPIGenerator
9
+ from .schema_loader import SchemaLoader
10
+ from .command_integration import CommandIntegrator
11
+ from .openapi_registry import OpenAPIRegistry
12
+ from .custom_openapi import custom_openapi, custom_openapi_with_fallback
13
+
14
+ __all__ = [
15
+ "CustomOpenAPIGenerator",
16
+ "SchemaLoader",
17
+ "CommandIntegrator",
18
+ "OpenAPIRegistry",
19
+ "custom_openapi",
20
+ "custom_openapi_with_fallback",
21
+ ]
@@ -0,0 +1,105 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Command integration utilities for OpenAPI generation.
6
+ """
7
+
8
+ from typing import Dict, Any, Type
9
+
10
+ from mcp_proxy_adapter.commands.command_registry import registry
11
+ from mcp_proxy_adapter.commands.base import Command
12
+ from mcp_proxy_adapter.core.logging import get_global_logger
13
+
14
+
15
+ class CommandIntegrator:
16
+ """Integrator for adding commands to OpenAPI schema."""
17
+
18
+ def __init__(self):
19
+ """Initialize command integrator."""
20
+ self.logger = get_global_logger()
21
+
22
+
23
+ def _create_params_schema(self, cmd_class: Type[Command]) -> Dict[str, Any]:
24
+ """
25
+ Create a schema for command parameters.
26
+
27
+ Args:
28
+ cmd_class: The command class to create schema for.
29
+
30
+ Returns:
31
+ Dict containing the parameter schema.
32
+ """
33
+ try:
34
+ # Get the command schema
35
+ schema = cmd_class.get_schema()
36
+
37
+ if not schema or "properties" not in schema:
38
+ return {"type": "object", "properties": {}}
39
+
40
+ # Convert to OpenAPI format
41
+ openapi_schema = {
42
+ "type": "object",
43
+ "properties": {},
44
+ "required": schema.get("required", [])
45
+ }
46
+
47
+ # Convert properties
48
+ for prop_name, prop_schema in schema["properties"].items():
49
+ openapi_schema["properties"][prop_name] = self._convert_property_schema(prop_schema)
50
+
51
+ return openapi_schema
52
+
53
+ except Exception as e:
54
+ self.logger.warning(f"Failed to create params schema for {cmd_class.__name__}: {e}")
55
+ return {"type": "object", "properties": {}}
56
+
57
+ def _convert_property_schema(self, prop_schema: Dict[str, Any]) -> Dict[str, Any]:
58
+ """
59
+ Convert property schema to OpenAPI format.
60
+
61
+ Args:
62
+ prop_schema: Property schema to convert.
63
+
64
+ Returns:
65
+ OpenAPI property schema.
66
+ """
67
+ openapi_prop = {}
68
+
69
+ # Handle type
70
+ if "type" in prop_schema:
71
+ openapi_prop["type"] = prop_schema["type"]
72
+
73
+ # Handle description
74
+ if "description" in prop_schema:
75
+ openapi_prop["description"] = prop_schema["description"]
76
+
77
+ # Handle default
78
+ if "default" in prop_schema:
79
+ openapi_prop["default"] = prop_schema["default"]
80
+
81
+ # Handle enum
82
+ if "enum" in prop_schema:
83
+ openapi_prop["enum"] = prop_schema["enum"]
84
+
85
+ # Handle minimum/maximum
86
+ if "minimum" in prop_schema:
87
+ openapi_prop["minimum"] = prop_schema["minimum"]
88
+ if "maximum" in prop_schema:
89
+ openapi_prop["maximum"] = prop_schema["maximum"]
90
+
91
+ # Handle minLength/maxLength
92
+ if "minLength" in prop_schema:
93
+ openapi_prop["minLength"] = prop_schema["minLength"]
94
+ if "maxLength" in prop_schema:
95
+ openapi_prop["maxLength"] = prop_schema["maxLength"]
96
+
97
+ # Handle pattern
98
+ if "pattern" in prop_schema:
99
+ openapi_prop["pattern"] = prop_schema["pattern"]
100
+
101
+ # Handle items for arrays
102
+ if "items" in prop_schema:
103
+ openapi_prop["items"] = self._convert_property_schema(prop_schema["items"])
104
+
105
+ return openapi_prop
@@ -0,0 +1,40 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Main OpenAPI generator for MCP Proxy Adapter.
6
+ """
7
+
8
+ from copy import deepcopy
9
+ from typing import Any, Dict, Optional
10
+
11
+ from fastapi import FastAPI
12
+
13
+ from mcp_proxy_adapter.core.logging import get_global_logger
14
+ from .schema_loader import SchemaLoader
15
+ from .command_integration import CommandIntegrator
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.logger = get_global_logger()
37
+ self.schema_loader = SchemaLoader()
38
+ self.command_integrator = CommandIntegrator()
39
+ self.base_schema = self.schema_loader.load_base_schema()
40
+
@@ -0,0 +1,62 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Registry for OpenAPI generators.
6
+ """
7
+
8
+ from typing import Dict, Callable, Optional, List
9
+
10
+ from mcp_proxy_adapter.core.logging import get_global_logger
11
+
12
+
13
+ class OpenAPIRegistry:
14
+ """Registry for OpenAPI generators."""
15
+
16
+ def __init__(self):
17
+ """Initialize OpenAPI registry."""
18
+ self.logger = get_global_logger()
19
+ self._generators: Dict[str, Callable] = {}
20
+
21
+ def register_generator(self, name: str, generator: Callable) -> None:
22
+ """
23
+ Register an OpenAPI generator.
24
+
25
+ Args:
26
+ name: Generator name
27
+ generator: Generator function
28
+ """
29
+ self._generators[name] = generator
30
+ self.logger.debug(f"Registered OpenAPI generator: {name}")
31
+
32
+ def get_generator(self, name: str) -> Optional[Callable]:
33
+ """
34
+ Get an OpenAPI generator by name.
35
+
36
+ Args:
37
+ name: Generator name
38
+
39
+ Returns:
40
+ Generator function or None if not found
41
+ """
42
+ return self._generators.get(name)
43
+
44
+ def list_generators(self) -> List[str]:
45
+ """
46
+ List all registered generators.
47
+
48
+ Returns:
49
+ List of generator names
50
+ """
51
+ return list(self._generators.keys())
52
+
53
+
54
+
55
+ # Global registry instance
56
+ _registry = OpenAPIRegistry()
57
+
58
+
59
+
60
+
61
+
62
+
@@ -0,0 +1,116 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Schema loading utilities for OpenAPI generation.
6
+ """
7
+
8
+ import json
9
+ from pathlib import Path
10
+ from typing import Dict, Any
11
+
12
+ from mcp_proxy_adapter.core.logging import get_global_logger
13
+
14
+
15
+ class SchemaLoader:
16
+ """Loader for OpenAPI base schemas."""
17
+
18
+ def __init__(self):
19
+ """Initialize schema loader."""
20
+ self.logger = get_global_logger()
21
+ self.base_schema_path = (
22
+ Path(__file__).parent.parent.parent / "schemas" / "openapi_schema.json"
23
+ )
24
+
25
+
26
+ def get_fallback_schema(self) -> Dict[str, Any]:
27
+ """
28
+ Get a fallback OpenAPI schema when the base schema file is not available.
29
+
30
+ Returns:
31
+ Dict containing a basic OpenAPI schema.
32
+ """
33
+ return {
34
+ "openapi": "3.0.2",
35
+ "info": {
36
+ "title": "MCP Microservice API",
37
+ "description": "API для выполнения команд микросервиса",
38
+ "version": "1.0.0"
39
+ },
40
+ "paths": {
41
+ "/cmd": {
42
+ "post": {
43
+ "summary": "Execute Command",
44
+ "description": "Executes a command via JSON-RPC protocol.",
45
+ "operationId": "execute_command",
46
+ "requestBody": {
47
+ "content": {
48
+ "application/json": {
49
+ "schema": {
50
+ "oneOf": [
51
+ { "$ref": "#/components/schemas/CommandRequest" },
52
+ { "$ref": "#/components/schemas/JsonRpcRequest" }
53
+ ]
54
+ }
55
+ }
56
+ },
57
+ "required": True
58
+ },
59
+ "responses": {
60
+ "200": {
61
+ "description": "Successful Response",
62
+ "content": {
63
+ "application/json": {
64
+ "schema": {
65
+ "oneOf": [
66
+ { "$ref": "#/components/schemas/CommandResponse" },
67
+ { "$ref": "#/components/schemas/JsonRpcResponse" }
68
+ ]
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ },
77
+ "components": {
78
+ "schemas": {
79
+ "CommandRequest": {
80
+ "type": "object",
81
+ "properties": {
82
+ "command": {"type": "string"},
83
+ "params": {"type": "object"}
84
+ },
85
+ "required": ["command"]
86
+ },
87
+ "CommandResponse": {
88
+ "type": "object",
89
+ "properties": {
90
+ "success": {"type": "boolean"},
91
+ "data": {"type": "object"},
92
+ "error": {"type": "string"}
93
+ }
94
+ },
95
+ "JsonRpcRequest": {
96
+ "type": "object",
97
+ "properties": {
98
+ "jsonrpc": {"type": "string", "enum": ["2.0"]},
99
+ "method": {"type": "string"},
100
+ "params": {"type": "object"},
101
+ "id": {"type": "string"}
102
+ },
103
+ "required": ["jsonrpc", "method", "id"]
104
+ },
105
+ "JsonRpcResponse": {
106
+ "type": "object",
107
+ "properties": {
108
+ "jsonrpc": {"type": "string", "enum": ["2.0"]},
109
+ "result": {"type": "object"},
110
+ "error": {"type": "object"},
111
+ "id": {"type": "string"}
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
@@ -202,67 +202,6 @@ class APIToolDescription:
202
202
  return description
203
203
 
204
204
  @classmethod
205
- def generate_tool_description_text(cls, name: str, registry) -> str:
206
- """
207
- Генерирует текстовое описание инструмента API для документации.
208
-
209
- Args:
210
- name: Имя инструмента API
211
- registry: Реестр команд
212
-
213
- Returns:
214
- Текстовое описание инструмента в формате markdown
215
- """
216
- tool_data = cls.generate_tool_description(name, registry)
217
-
218
- # Формируем заголовок и базовое описание
219
- text = f"# Инструмент {tool_data['name']}\n\n"
220
- text += f"{tool_data['description']}\n\n"
221
-
222
- # Список доступных команд
223
- text += "## Доступные команды\n\n"
224
- for cmd_name, cmd_info in tool_data["supported_commands"].items():
225
- text += f"### {cmd_name}\n\n"
226
- text += f"{cmd_info['description']}\n\n"
227
-
228
- # Информация о параметрах
229
- if cmd_info["params"]:
230
- text += "#### Параметры:\n\n"
231
- for param_name, param_info in cmd_info["params"].items():
232
- required_mark = (
233
- "**обязательный**" if param_info["required"] else "опциональный"
234
- )
235
- text += f"- `{param_name}` ({param_info['type']}, {required_mark}): {param_info['description']}\n"
236
- text += "\n"
237
-
238
- # Примеры использования
239
- cmd_examples = [
240
- ex for ex in tool_data["examples"] if ex["command"] == cmd_name
241
- ]
242
- if cmd_examples:
243
- text += "#### Примеры:\n\n"
244
- for i, example in enumerate(cmd_examples):
245
- text += f"**Пример {i+1}**: {example['description']}\n"
246
- text += "```json\n"
247
- text += "{\n"
248
- text += f' "command": "{example["command"]}",\n'
249
- if example["params"]:
250
- text += ' "params": {\n'
251
- params_str = []
252
- for p_name, p_value in example["params"].items():
253
- if isinstance(p_value, str):
254
- p_str = f' "{p_name}": "{p_value}"'
255
- else:
256
- p_str = f' "{p_name}": {p_value}'
257
- params_str.append(p_str)
258
- text += ",\n".join(params_str)
259
- text += "\n }\n"
260
- else:
261
- text += ' "params": {}\n'
262
- text += "}\n"
263
- text += "```\n\n"
264
-
265
- return text
266
205
 
267
206
  @classmethod
268
207
  def _simplify_type(cls, type_str: str) -> str:
@@ -6,7 +6,6 @@
6
6
  и других API интерфейсов.
7
7
  """
8
8
 
9
- from typing import Any, Dict, List, Optional, Union
10
9
  import json
11
10
  import logging
12
11
 
@@ -79,72 +78,8 @@ class ToolIntegration:
79
78
  return schema
80
79
 
81
80
  @classmethod
82
- def generate_tool_documentation(
83
- cls, tool_name: str, registry: CommandRegistry, format: str = "markdown"
84
- ) -> str:
85
- """
86
- Генерирует документацию по инструменту API в заданном формате.
87
-
88
- Args:
89
- tool_name: Имя инструмента API
90
- registry: Реестр команд
91
- format: Формат документации (markdown, html)
92
-
93
- Returns:
94
- Строка с документацией в заданном формате
95
- """
96
- if format.lower() == "markdown":
97
- return APIToolDescription.generate_tool_description_text(
98
- tool_name, registry
99
- )
100
- elif format.lower() == "html":
101
- # Преобразуем markdown в HTML (в реальном проекте здесь будет
102
- # использоваться библиотека для конвертации markdown в HTML)
103
- markdown = APIToolDescription.generate_tool_description_text(
104
- tool_name, registry
105
- )
106
- # Простая конвертация для примера
107
- body = markdown.replace("#", "<h1>").replace("\n\n", "</p><p>")
108
- html = f"<html><body>{body}</body></html>"
109
- return html
110
- else:
111
- # По умолчанию возвращаем markdown
112
- return APIToolDescription.generate_tool_description_text(
113
- tool_name, registry
114
- )
115
81
 
116
82
  @classmethod
117
- def register_external_tools(
118
- cls, registry: CommandRegistry, tool_names: List[str]
119
- ) -> Dict[str, Dict[str, Any]]:
120
- """
121
- Регистрирует инструменты API во внешних системах.
122
-
123
- Args:
124
- registry: Реестр команд
125
- tool_names: Список имен инструментов API для регистрации
126
-
127
- Returns:
128
- Словарь с результатами регистрации инструментов
129
- """
130
- results = {}
131
-
132
- for tool_name in tool_names:
133
- try:
134
- # Генерируем схему инструмента
135
- schema = cls.generate_tool_schema(tool_name, registry)
136
-
137
- # Здесь будет код для регистрации инструмента во внешней системе
138
- # Например, отправка схемы в API регистрации инструментов
139
-
140
- results[tool_name] = {"status": "success", "schema": schema}
141
-
142
- get_global_logger().info(f"Successfully registered tool: {tool_name}")
143
- except Exception as e:
144
- get_global_logger().debug(f"Error registering tool {tool_name}: {e}")
145
- results[tool_name] = {"status": "error", "error": str(e)}
146
-
147
- return results
148
83
 
149
84
  @classmethod
150
85
  def _extract_parameter_types(
@@ -194,55 +129,3 @@ class ToolIntegration:
194
129
  return parameter_types
195
130
 
196
131
 
197
- def generate_tool_help(tool_name: str, registry: CommandRegistry) -> str:
198
- """
199
- Генерирует справочную информацию по инструменту API.
200
-
201
- Args:
202
- tool_name: Имя инструмента API
203
- registry: Реестр команд
204
-
205
- Returns:
206
- Строка с описанием инструмента и доступных команд
207
- """
208
- # Получаем метаданные всех команд
209
- all_metadata = registry.get_all_metadata()
210
-
211
- # Формируем текст справки
212
- help_text = f"# Инструмент {tool_name}\n\n"
213
- help_text += "Позволяет выполнять команды через JSON-RPC протокол.\n\n"
214
- help_text += "## Доступные команды:\n\n"
215
-
216
- # Добавляем информацию о каждой команде
217
- for cmd_name, metadata in all_metadata.items():
218
- help_text += f"### {cmd_name}\n"
219
- help_text += f"{metadata['summary']}\n\n"
220
-
221
- # Добавляем информацию о параметрах команды
222
- if metadata["params"]:
223
- help_text += "Параметры:\n"
224
- for param_name, param_info in metadata["params"].items():
225
- required = (
226
- "обязательный"
227
- if param_info.get("required", False)
228
- else "опциональный"
229
- )
230
- help_text += f"- {param_name}: {required}\n"
231
- help_text += "\n"
232
-
233
- # Добавляем пример использования команды
234
- if metadata.get("examples"):
235
- example = metadata["examples"][0]
236
- help_text += "Пример:\n"
237
- help_text += "```json\n"
238
- help_text += json.dumps(
239
- {
240
- "command": example.get("command", cmd_name),
241
- "params": example.get("params", {}),
242
- },
243
- indent=2,
244
- ensure_ascii=False,
245
- )
246
- help_text += "\n```\n\n"
247
-
248
- return help_text