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.
- mcp_proxy_adapter/core/proxy_registration.py +100 -68
- mcp_proxy_adapter/custom_openapi.py +294 -2
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +284 -0
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
- mcp_proxy_adapter/examples/config_builder.py +574 -0
- mcp_proxy_adapter/examples/config_cli.py +283 -0
- mcp_proxy_adapter/examples/create_test_configs.py +169 -266
- mcp_proxy_adapter/examples/generate_certificates_bugfix.py +374 -0
- mcp_proxy_adapter/examples/generate_certificates_cli.py +406 -0
- mcp_proxy_adapter/examples/generate_certificates_fixed.py +313 -0
- mcp_proxy_adapter/examples/generate_certificates_framework.py +366 -0
- mcp_proxy_adapter/examples/generate_certificates_openssl.py +391 -0
- mcp_proxy_adapter/examples/required_certificates.py +210 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +117 -13
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +42 -26
- mcp_proxy_adapter/examples/security_test_client.py +332 -85
- mcp_proxy_adapter/examples/test_config_builder.py +450 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +136 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/METADATA +81 -1
- {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/RECORD +28 -12
- mcp_proxy_adapter-6.4.46.dist-info/entry_points.txt +12 -0
- mcp_proxy_adapter-6.4.44.dist-info/entry_points.txt +0 -2
- {mcp_proxy_adapter-6.4.44.dist-info → mcp_proxy_adapter-6.4.46.dist-info}/WHEEL +0 -0
- {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
|
-
#
|
72
|
-
self.
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
"
|
85
|
-
"Please specify a
|
79
|
+
"proxy_url is required in registration configuration. "
|
80
|
+
"Please specify a valid proxy URL in your configuration."
|
86
81
|
)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
-
"
|
94
|
-
"Please specify a
|
137
|
+
"heartbeat.timeout is required in registration configuration. "
|
138
|
+
"Please specify a timeout value."
|
95
139
|
)
|
96
|
-
|
97
|
-
|
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
|
-
"
|
103
|
-
"Please specify a
|
143
|
+
"heartbeat.retry_attempts is required in registration configuration. "
|
144
|
+
"Please specify a retry_attempts value."
|
104
145
|
)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
"
|
112
|
-
"Please specify a
|
154
|
+
"heartbeat.retry_delay is required in registration configuration. "
|
155
|
+
"Please specify a retry_delay value."
|
113
156
|
)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
self.
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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.
|
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
|
-
|
49
|
-
|
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
|
"""
|