mcp-proxy-adapter 6.4.44__py3-none-any.whl → 6.4.46__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 (29) hide show
  1. mcp_proxy_adapter/core/proxy_registration.py +100 -68
  2. mcp_proxy_adapter/custom_openapi.py +294 -2
  3. mcp_proxy_adapter/examples/bugfix_certificate_config.py +284 -0
  4. mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
  5. mcp_proxy_adapter/examples/config_builder.py +574 -0
  6. mcp_proxy_adapter/examples/config_cli.py +283 -0
  7. mcp_proxy_adapter/examples/create_test_configs.py +169 -266
  8. mcp_proxy_adapter/examples/generate_certificates_bugfix.py +374 -0
  9. mcp_proxy_adapter/examples/generate_certificates_cli.py +406 -0
  10. mcp_proxy_adapter/examples/generate_certificates_fixed.py +313 -0
  11. mcp_proxy_adapter/examples/generate_certificates_framework.py +366 -0
  12. mcp_proxy_adapter/examples/generate_certificates_openssl.py +391 -0
  13. mcp_proxy_adapter/examples/required_certificates.py +210 -0
  14. mcp_proxy_adapter/examples/run_full_test_suite.py +117 -13
  15. mcp_proxy_adapter/examples/run_security_tests_fixed.py +42 -26
  16. mcp_proxy_adapter/examples/security_test_client.py +332 -85
  17. mcp_proxy_adapter/examples/test_config_builder.py +450 -0
  18. mcp_proxy_adapter/examples/update_config_certificates.py +136 -0
  19. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  20. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  21. mcp_proxy_adapter/schemas/roles.json +37 -0
  22. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  23. mcp_proxy_adapter/version.py +1 -1
  24. {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/METADATA +81 -1
  25. {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/RECORD +28 -12
  26. mcp_proxy_adapter-6.4.46.dist-info/entry_points.txt +12 -0
  27. mcp_proxy_adapter-6.4.44.dist-info/entry_points.txt +0 -2
  28. {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/WHEEL +0 -0
  29. {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/top_level.txt +0 -0
@@ -68,84 +68,116 @@ class ProxyRegistrationManager:
68
68
  except Exception:
69
69
  pass
70
70
 
71
- # Basic registration settings
72
- self.proxy_url = self.registration_config.get("proxy_url")
73
- if not self.proxy_url:
74
- raise ValueError(
75
- "proxy_url is required in registration configuration. "
76
- "Please specify a valid proxy URL in your configuration."
77
- )
78
- self.server_id = self.registration_config.get("server_id")
79
- if not self.server_id:
80
- # Try to get from proxy_info.name as fallback
81
- self.server_id = self.registration_config.get("proxy_info", {}).get("name")
82
- if not self.server_id:
71
+ # Check if registration is enabled
72
+ self.enabled = self.registration_config.get("enabled", False)
73
+
74
+ # Basic registration settings - only validate if enabled
75
+ if self.enabled:
76
+ self.proxy_url = self.registration_config.get("proxy_url")
77
+ if not self.proxy_url:
83
78
  raise ValueError(
84
- "server_id is required in registration configuration. "
85
- "Please specify a server_id or proxy_info.name in your configuration."
79
+ "proxy_url is required in registration configuration. "
80
+ "Please specify a valid proxy URL in your configuration."
86
81
  )
87
- self.server_name = self.registration_config.get("server_name")
88
- if not self.server_name:
89
- # Try to get from proxy_info.name as fallback
90
- self.server_name = self.registration_config.get("proxy_info", {}).get("name")
82
+ else:
83
+ self.proxy_url = None
84
+
85
+ if self.enabled:
86
+ self.server_id = self.registration_config.get("server_id")
87
+ if not self.server_id:
88
+ # Try to get from proxy_info.name as fallback
89
+ self.server_id = self.registration_config.get("proxy_info", {}).get("name")
90
+ if not self.server_id:
91
+ raise ValueError(
92
+ "server_id is required in registration configuration. "
93
+ "Please specify a server_id or proxy_info.name in your configuration."
94
+ )
95
+ self.server_name = self.registration_config.get("server_name")
91
96
  if not self.server_name:
97
+ # Try to get from proxy_info.name as fallback
98
+ self.server_name = self.registration_config.get("proxy_info", {}).get("name")
99
+ if not self.server_name:
100
+ raise ValueError(
101
+ "server_name is required in registration configuration. "
102
+ "Please specify a server_name or proxy_info.name in your configuration."
103
+ )
104
+ self.description = self.registration_config.get("description")
105
+ if not self.description:
106
+ # Try to get from proxy_info.description as fallback
107
+ self.description = self.registration_config.get("proxy_info", {}).get("description")
108
+ if not self.description:
109
+ raise ValueError(
110
+ "description is required in registration configuration. "
111
+ "Please specify a description or proxy_info.description in your configuration."
112
+ )
113
+ else:
114
+ self.server_id = None
115
+ self.server_name = None
116
+ self.description = None
117
+
118
+ if self.enabled:
119
+ self.version = self.registration_config.get("version")
120
+ if not self.version:
121
+ # Try to get from proxy_info.version as fallback
122
+ self.version = self.registration_config.get("proxy_info", {}).get("version")
123
+ if not self.version:
124
+ raise ValueError(
125
+ "version is required in registration configuration. "
126
+ "Please specify a version or proxy_info.version in your configuration."
127
+ )
128
+ else:
129
+ self.version = None
130
+
131
+ # Heartbeat settings - only validate if enabled
132
+ if self.enabled:
133
+ heartbeat_config = self.registration_config.get("heartbeat", {})
134
+ self.timeout = heartbeat_config.get("timeout")
135
+ if self.timeout is None:
92
136
  raise ValueError(
93
- "server_name is required in registration configuration. "
94
- "Please specify a server_name or proxy_info.name in your configuration."
137
+ "heartbeat.timeout is required in registration configuration. "
138
+ "Please specify a timeout value."
95
139
  )
96
- self.description = self.registration_config.get("description")
97
- if not self.description:
98
- # Try to get from proxy_info.description as fallback
99
- self.description = self.registration_config.get("proxy_info", {}).get("description")
100
- if not self.description:
140
+ self.retry_attempts = heartbeat_config.get("retry_attempts")
141
+ if self.retry_attempts is None:
101
142
  raise ValueError(
102
- "description is required in registration configuration. "
103
- "Please specify a description or proxy_info.description in your configuration."
143
+ "heartbeat.retry_attempts is required in registration configuration. "
144
+ "Please specify a retry_attempts value."
104
145
  )
105
- self.version = self.registration_config.get("version")
106
- if not self.version:
107
- # Try to get from proxy_info.version as fallback
108
- self.version = self.registration_config.get("proxy_info", {}).get("version")
109
- if not self.version:
146
+ else:
147
+ self.timeout = None
148
+ self.retry_attempts = None
149
+
150
+ if self.enabled:
151
+ self.retry_delay = heartbeat_config.get("retry_delay")
152
+ if self.retry_delay is None:
110
153
  raise ValueError(
111
- "version is required in registration configuration. "
112
- "Please specify a version or proxy_info.version in your configuration."
154
+ "heartbeat.retry_delay is required in registration configuration. "
155
+ "Please specify a retry_delay value."
113
156
  )
114
-
115
- # Heartbeat settings
116
- heartbeat_config = self.registration_config.get("heartbeat", {})
117
- self.timeout = heartbeat_config.get("timeout")
118
- if self.timeout is None:
119
- raise ValueError(
120
- "heartbeat.timeout is required in registration configuration. "
121
- "Please specify a timeout value."
122
- )
123
- self.retry_attempts = heartbeat_config.get("retry_attempts")
124
- if self.retry_attempts is None:
125
- raise ValueError(
126
- "heartbeat.retry_attempts is required in registration configuration. "
127
- "Please specify a retry_attempts value."
128
- )
129
- self.retry_delay = heartbeat_config.get("retry_delay")
130
- if self.retry_delay is None:
131
- raise ValueError(
132
- "heartbeat.retry_delay is required in registration configuration. "
133
- "Please specify a retry_delay value."
134
- )
135
- self.heartbeat_interval = heartbeat_config.get("interval")
136
- if self.heartbeat_interval is None:
137
- raise ValueError(
138
- "heartbeat.interval is required in registration configuration. "
139
- "Please specify an interval value."
140
- )
157
+ else:
158
+ self.retry_delay = None
159
+
160
+ if self.enabled:
161
+ self.heartbeat_interval = heartbeat_config.get("interval")
162
+ if self.heartbeat_interval is None:
163
+ raise ValueError(
164
+ "heartbeat.interval is required in registration configuration. "
165
+ "Please specify an interval value."
166
+ )
167
+ else:
168
+ self.heartbeat_interval = None
141
169
 
142
170
  # Auto registration settings
143
- self.auto_register = self.registration_config.get("enabled")
144
- if self.auto_register is None:
145
- raise ValueError(
146
- "enabled is required in registration configuration. "
147
- "Please specify whether registration is enabled (true/false)."
148
- )
171
+ if self.enabled:
172
+ self.auto_register = self.registration_config.get("enabled")
173
+ if self.auto_register is None:
174
+ raise ValueError(
175
+ "enabled is required in registration configuration. "
176
+ "Please specify whether registration is enabled (true/false)."
177
+ )
178
+ else:
179
+ self.auto_register = False
180
+
149
181
  self.auto_unregister = True # Always unregister on shutdown
150
182
 
151
183
  # Initialize client security manager
@@ -168,7 +200,7 @@ class ProxyRegistrationManager:
168
200
  Returns:
169
201
  True if registration is enabled, False otherwise.
170
202
  """
171
- return self.registration_config.get("enabled", False)
203
+ return self.enabled
172
204
 
173
205
  def set_server_url(self, server_url: str) -> None:
174
206
  """
@@ -45,8 +45,300 @@ class CustomOpenAPIGenerator:
45
45
  Returns:
46
46
  Dict containing the base OpenAPI schema.
47
47
  """
48
- with open(self.base_schema_path, "r", encoding="utf-8") as f:
49
- return json.load(f)
48
+ try:
49
+ with open(self.base_schema_path, "r", encoding="utf-8") as f:
50
+ return json.load(f)
51
+ except FileNotFoundError:
52
+ 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
+ }
50
342
 
51
343
  def _add_commands_to_schema(self, schema: Dict[str, Any]) -> None:
52
344
  """