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
@@ -1,317 +1,220 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
"""
|
3
3
|
Test Configuration Generator
|
4
|
-
Creates test configurations
|
4
|
+
Creates test configurations using the advanced ConfigBuilder utility.
|
5
5
|
Author: Vasiliy Zdanovskiy
|
6
6
|
email: vasilyvz@gmail.com
|
7
7
|
"""
|
8
8
|
import json
|
9
|
-
import shutil
|
10
9
|
import uuid
|
11
10
|
from pathlib import Path
|
12
11
|
from typing import Dict, Any, Optional
|
13
12
|
|
13
|
+
from config_builder import ConfigBuilder, ConfigFactory, Protocol, AuthMethod
|
14
|
+
|
14
15
|
|
15
16
|
class TestConfigGenerator:
|
16
|
-
"""Generator for test configurations
|
17
|
+
"""Generator for test configurations using ConfigBuilder."""
|
17
18
|
|
18
|
-
def __init__(self,
|
19
|
+
def __init__(self, output_dir: str = "configs"):
|
19
20
|
"""
|
20
21
|
Initialize the generator.
|
21
22
|
|
22
23
|
Args:
|
23
|
-
comprehensive_config_path: Path to the comprehensive configuration file
|
24
24
|
output_dir: Directory to output test configurations
|
25
25
|
"""
|
26
|
-
self.comprehensive_config_path = Path(comprehensive_config_path)
|
27
26
|
self.output_dir = Path(output_dir)
|
28
27
|
self.output_dir.mkdir(exist_ok=True)
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
self.base_config = json.load(f)
|
33
|
-
|
34
|
-
def create_config(self, name: str, modifications: Dict[str, Any]) -> Path:
|
35
|
-
"""
|
36
|
-
Create a test configuration with specific modifications.
|
37
|
-
|
38
|
-
Args:
|
39
|
-
name: Name of the configuration (without .json extension)
|
40
|
-
modifications: Dictionary of modifications to apply
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
Path to the created configuration file
|
44
|
-
"""
|
45
|
-
# Deep copy the base config
|
46
|
-
config = json.loads(json.dumps(self.base_config))
|
47
|
-
|
48
|
-
# Add UUID if not present
|
49
|
-
if "uuid" not in config:
|
50
|
-
config["uuid"] = str(uuid.uuid4())
|
51
|
-
|
52
|
-
# Apply modifications
|
53
|
-
for key, value in modifications.items():
|
54
|
-
self._set_nested_value(config, key, value)
|
55
|
-
|
56
|
-
# Save the configuration
|
29
|
+
def _save_config(self, name: str, config: Dict[str, Any]) -> Path:
|
30
|
+
"""Save configuration to file."""
|
57
31
|
output_path = self.output_dir / f"{name}.json"
|
58
32
|
with open(output_path, 'w', encoding='utf-8') as f:
|
59
33
|
json.dump(config, f, indent=2, ensure_ascii=False)
|
60
|
-
|
61
34
|
print(f"✅ Created test config: {output_path}")
|
62
35
|
return output_path
|
63
36
|
|
64
|
-
def _set_nested_value(self, config: Dict, key: str, value: Any):
|
65
|
-
"""Set a nested value in the configuration using dot notation."""
|
66
|
-
keys = key.split('.')
|
67
|
-
current = config
|
68
|
-
|
69
|
-
for k in keys[:-1]:
|
70
|
-
if k not in current:
|
71
|
-
current[k] = {}
|
72
|
-
current = current[k]
|
73
|
-
|
74
|
-
current[keys[-1]] = value
|
75
|
-
|
76
37
|
def create_all_test_configs(self):
|
77
|
-
"""Create all standard test configurations."""
|
78
|
-
print("🔧 Creating test configurations
|
38
|
+
"""Create all standard test configurations using ConfigFactory."""
|
39
|
+
print("🔧 Creating test configurations using ConfigBuilder...")
|
79
40
|
|
80
|
-
#
|
81
|
-
self.
|
82
|
-
"server.port": 20020, # Dedicated port for basic_http
|
83
|
-
"ssl.enabled": False,
|
84
|
-
"security.enabled": False,
|
85
|
-
"proxy_registration.enabled": False,
|
86
|
-
"protocols.allowed_protocols": ["http"],
|
87
|
-
"protocols.default_protocol": "http"
|
88
|
-
})
|
41
|
+
# Create output directory
|
42
|
+
self.output_dir.mkdir(exist_ok=True)
|
89
43
|
|
90
|
-
#
|
91
|
-
self.
|
92
|
-
|
93
|
-
"ssl.enabled": False,
|
94
|
-
"security.enabled": True,
|
95
|
-
"security.auth.enabled": True,
|
96
|
-
"security.auth.methods": ["api_key"],
|
97
|
-
"security.auth.api_keys": {
|
98
|
-
"admin": "admin-secret-key",
|
99
|
-
"user": "user-secret-key"
|
100
|
-
},
|
101
|
-
"proxy_registration.enabled": True,
|
102
|
-
"proxy_registration.auth_method": "token",
|
103
|
-
"proxy_registration.server_url": "https://127.0.0.1:20005/register",
|
104
|
-
"proxy_registration.proxy_url": "https://127.0.0.1:20005",
|
105
|
-
"proxy_registration.server_id": "http_token_server",
|
106
|
-
"proxy_registration.server_name": "HTTP Token Server",
|
107
|
-
"proxy_registration.description": "HTTP server with token authentication",
|
108
|
-
"proxy_registration.version": "1.0.0",
|
109
|
-
"proxy_registration.token.enabled": True,
|
110
|
-
"proxy_registration.token.token": "http_token_123",
|
111
|
-
"proxy_registration.heartbeat.enabled": True,
|
112
|
-
"proxy_registration.heartbeat.interval": 30,
|
113
|
-
"proxy_registration.heartbeat.timeout": 10,
|
114
|
-
"proxy_registration.heartbeat.retry_attempts": 3,
|
115
|
-
"proxy_registration.heartbeat.retry_delay": 5,
|
116
|
-
"protocols.allowed_protocols": ["http"],
|
117
|
-
"protocols.default_protocol": "http"
|
118
|
-
})
|
44
|
+
# 1. HTTP Simple
|
45
|
+
config = ConfigFactory.create_http_simple(port=20020, log_dir=str(self.output_dir.parent / "logs"))
|
46
|
+
self._save_config("http_simple", config)
|
119
47
|
|
120
|
-
#
|
121
|
-
|
122
|
-
"server.port": 20023, # Dedicated port for https_token
|
123
|
-
"ssl.enabled": True,
|
124
|
-
"ssl.cert_file": "certs/mcp_proxy_adapter_server.crt",
|
125
|
-
"ssl.key_file": "certs/mcp_proxy_adapter_server.key",
|
126
|
-
"ssl.ca_cert": "certs/mcp_proxy_adapter_ca_ca.crt",
|
127
|
-
"security.enabled": True,
|
128
|
-
"security.auth.enabled": True,
|
129
|
-
"security.auth.methods": ["api_key"],
|
130
|
-
"security.auth.api_keys": {
|
48
|
+
# 2. HTTP with Token Auth
|
49
|
+
api_keys = {
|
131
50
|
"admin": "admin-secret-key",
|
132
51
|
"user": "user-secret-key"
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
self.
|
155
|
-
"server.port": 20022, # Dedicated port for https_simple
|
156
|
-
"ssl.enabled": True,
|
157
|
-
"ssl.cert_file": "certs/mcp_proxy_adapter_server.crt",
|
158
|
-
"ssl.key_file": "certs/mcp_proxy_adapter_server.key",
|
159
|
-
"ssl.ca_cert": "certs/mcp_proxy_adapter_ca_ca.crt",
|
160
|
-
"security.enabled": False,
|
161
|
-
"proxy_registration.enabled": False,
|
162
|
-
"protocols.allowed_protocols": ["https"],
|
163
|
-
"protocols.default_protocol": "https"
|
164
|
-
})
|
52
|
+
}
|
53
|
+
config = ConfigFactory.create_http_token(port=20021, log_dir=str(self.output_dir.parent / "logs"), api_keys=api_keys)
|
54
|
+
self._save_config("http_token", config)
|
55
|
+
|
56
|
+
# 3. HTTPS Simple
|
57
|
+
config = ConfigFactory.create_https_simple(
|
58
|
+
port=20022,
|
59
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
60
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
61
|
+
key_dir=str(self.output_dir.parent / "keys")
|
62
|
+
)
|
63
|
+
self._save_config("https_simple", config)
|
64
|
+
|
65
|
+
# 4. HTTPS with Token Auth
|
66
|
+
config = ConfigFactory.create_https_token(
|
67
|
+
port=20023,
|
68
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
69
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
70
|
+
key_dir=str(self.output_dir.parent / "keys"),
|
71
|
+
api_keys=api_keys
|
72
|
+
)
|
73
|
+
self._save_config("https_token", config)
|
165
74
|
|
166
75
|
# 5. mTLS Simple
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
"security.enabled": True,
|
175
|
-
"security.auth.enabled": True,
|
176
|
-
"security.auth.methods": ["certificate"],
|
177
|
-
"proxy_registration.enabled": False,
|
178
|
-
"protocols.allowed_protocols": ["https", "mtls"],
|
179
|
-
"protocols.default_protocol": "mtls"
|
180
|
-
})
|
76
|
+
config = ConfigFactory.create_mtls_simple(
|
77
|
+
port=20024,
|
78
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
79
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
80
|
+
key_dir=str(self.output_dir.parent / "keys")
|
81
|
+
)
|
82
|
+
self._save_config("mtls_simple", config)
|
181
83
|
|
182
84
|
# 6. mTLS with Roles
|
183
|
-
|
184
|
-
"
|
185
|
-
"
|
186
|
-
"
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
"protocols.allowed_protocols": ["https", "mtls"],
|
197
|
-
"protocols.default_protocol": "mtls"
|
198
|
-
})
|
199
|
-
|
200
|
-
# 6a. mTLS without Roles (for security tests)
|
201
|
-
self.create_config("mtls_no_roles", {
|
202
|
-
"server.port": 20024, # Dedicated port for mtls
|
203
|
-
"ssl.enabled": True,
|
204
|
-
"ssl.cert_file": "certs/localhost_server.crt",
|
205
|
-
"ssl.key_file": "keys/server_key.pem",
|
206
|
-
"ssl.ca_cert": "certs/mcp_proxy_adapter_ca_ca.crt",
|
207
|
-
"ssl.verify_client": True,
|
208
|
-
"security.enabled": True,
|
209
|
-
"security.auth.enabled": True,
|
210
|
-
"security.auth.methods": ["certificate"],
|
211
|
-
"security.permissions.enabled": False,
|
212
|
-
"proxy_registration.enabled": False,
|
213
|
-
"protocols.allowed_protocols": ["https", "mtls"],
|
214
|
-
"protocols.default_protocol": "mtls"
|
215
|
-
})
|
85
|
+
roles = {
|
86
|
+
"admin": ["read", "write", "delete", "admin"],
|
87
|
+
"user": ["read", "write"],
|
88
|
+
"guest": ["read"]
|
89
|
+
}
|
90
|
+
config = ConfigFactory.create_mtls_with_roles(
|
91
|
+
port=20025,
|
92
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
93
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
94
|
+
key_dir=str(self.output_dir.parent / "keys"),
|
95
|
+
roles=roles
|
96
|
+
)
|
97
|
+
self._save_config("mtls_with_roles", config)
|
216
98
|
|
217
99
|
# 7. mTLS with Proxy Registration
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
"
|
224
|
-
"
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
#
|
240
|
-
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
100
|
+
config = ConfigFactory.create_mtls_with_proxy(
|
101
|
+
port=20026,
|
102
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
103
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
104
|
+
key_dir=str(self.output_dir.parent / "keys"),
|
105
|
+
proxy_url="https://127.0.0.1:20005",
|
106
|
+
server_id="mcp_test_server"
|
107
|
+
)
|
108
|
+
self._save_config("mtls_with_proxy", config)
|
109
|
+
|
110
|
+
# 8. Full Featured Configuration
|
111
|
+
config = ConfigFactory.create_full_featured(
|
112
|
+
port=20027,
|
113
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
114
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
115
|
+
key_dir=str(self.output_dir.parent / "keys"),
|
116
|
+
proxy_url="https://127.0.0.1:20005",
|
117
|
+
server_id="mcp_full_server"
|
118
|
+
)
|
119
|
+
self._save_config("full_featured", config)
|
120
|
+
|
121
|
+
# 9. Additional configurations for comprehensive testing
|
122
|
+
|
123
|
+
# mTLS No Roles (for testing without role-based access)
|
124
|
+
config = ConfigFactory.create_mtls_simple(
|
125
|
+
port=20028,
|
126
|
+
log_dir=str(self.output_dir.parent / "logs"),
|
127
|
+
cert_dir=str(self.output_dir.parent / "certs"),
|
128
|
+
key_dir=str(self.output_dir.parent / "keys")
|
129
|
+
)
|
130
|
+
self._save_config("mtls_no_roles", config)
|
131
|
+
|
132
|
+
print(f"✅ Created {len(list(self.output_dir.glob('*.json')))} test configurations in {self.output_dir}/")
|
133
|
+
|
134
|
+
# Create roles.json file for role-based configurations
|
135
|
+
self._create_roles_file(roles)
|
136
|
+
|
137
|
+
def _create_roles_file(self, roles: Dict[str, list]):
|
138
|
+
"""Create roles.json file for role-based access control."""
|
139
|
+
roles_config = {
|
140
|
+
"enabled": True,
|
141
|
+
"default_policy": {
|
142
|
+
"deny_by_default": False,
|
143
|
+
"require_role_match": False,
|
144
|
+
"case_sensitive": False,
|
145
|
+
"allow_wildcard": False
|
255
146
|
},
|
256
|
-
"
|
257
|
-
"
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
})
|
147
|
+
"roles": roles,
|
148
|
+
"permissions": {
|
149
|
+
"read": ["GET"],
|
150
|
+
"write": ["POST", "PUT", "PATCH"],
|
151
|
+
"delete": ["DELETE"],
|
152
|
+
"admin": ["*"]
|
153
|
+
}
|
154
|
+
}
|
265
155
|
|
266
|
-
|
156
|
+
roles_path = self.output_dir / "roles.json"
|
157
|
+
with open(roles_path, 'w', encoding='utf-8') as f:
|
158
|
+
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
159
|
+
print(f"✅ Created roles.json: {roles_path}")
|
160
|
+
|
161
|
+
def create_custom_config(self, name: str, protocol: str, auth: str = "none",
|
162
|
+
port: int = 8000, **kwargs) -> Path:
|
163
|
+
"""
|
164
|
+
Create a custom configuration.
|
165
|
+
|
166
|
+
Args:
|
167
|
+
name: Configuration name
|
168
|
+
protocol: Protocol (http, https, mtls)
|
169
|
+
auth: Authentication method (none, token, basic)
|
170
|
+
port: Server port
|
171
|
+
**kwargs: Additional configuration parameters
|
172
|
+
|
173
|
+
Returns:
|
174
|
+
Path to created configuration file
|
175
|
+
"""
|
176
|
+
builder = ConfigBuilder()
|
177
|
+
|
178
|
+
# Set basic server configuration
|
179
|
+
builder.set_server(port=port, **kwargs.get('server', {}))
|
180
|
+
|
181
|
+
# Set protocol
|
182
|
+
protocol_enum = Protocol(protocol.lower())
|
183
|
+
cert_dir = kwargs.get('cert_dir', str(self.output_dir.parent / "certs"))
|
184
|
+
key_dir = kwargs.get('key_dir', str(self.output_dir.parent / "keys"))
|
185
|
+
builder.set_protocol(protocol_enum, cert_dir=cert_dir, key_dir=key_dir)
|
186
|
+
|
187
|
+
# Set authentication
|
188
|
+
auth_enum = AuthMethod(auth.lower())
|
189
|
+
api_keys = kwargs.get('api_keys')
|
190
|
+
roles = kwargs.get('roles')
|
191
|
+
builder.set_auth(auth_enum, api_keys=api_keys, roles=roles)
|
192
|
+
|
193
|
+
# Set proxy registration if specified
|
194
|
+
if kwargs.get('proxy_registration', False):
|
195
|
+
proxy_url = kwargs.get('proxy_url', 'https://127.0.0.1:20005')
|
196
|
+
server_id = kwargs.get('server_id', f'{name}_server')
|
197
|
+
builder.set_proxy_registration(enabled=True, proxy_url=proxy_url, server_id=server_id, cert_dir=cert_dir)
|
198
|
+
|
199
|
+
# Set debug if specified
|
200
|
+
if kwargs.get('debug', False):
|
201
|
+
builder.set_debug(enabled=True)
|
202
|
+
|
203
|
+
config = builder.build()
|
204
|
+
return self._save_config(name, config)
|
267
205
|
|
268
206
|
|
269
207
|
def main():
|
270
|
-
"""Main
|
271
|
-
|
272
|
-
|
273
|
-
parser = argparse.ArgumentParser(description="Generate test configurations")
|
274
|
-
parser.add_argument(
|
275
|
-
"--comprehensive-config",
|
276
|
-
default="comprehensive_config.json",
|
277
|
-
help="Path to comprehensive configuration file"
|
278
|
-
)
|
279
|
-
parser.add_argument(
|
280
|
-
"--output-dir",
|
281
|
-
default="configs",
|
282
|
-
help="Output directory for test configurations"
|
283
|
-
)
|
284
|
-
parser.add_argument(
|
285
|
-
"--config-name",
|
286
|
-
help="Create a specific configuration (http_simple, https_auth, mtls_with_roles, etc.)"
|
287
|
-
)
|
288
|
-
parser.add_argument(
|
289
|
-
"--modifications",
|
290
|
-
help="JSON string of modifications to apply (for custom configs)"
|
291
|
-
)
|
292
|
-
|
293
|
-
args = parser.parse_args()
|
208
|
+
"""Main function to create all test configurations."""
|
209
|
+
print("🔧 Creating Test Configurations")
|
210
|
+
print("=" * 40)
|
294
211
|
|
295
|
-
generator = TestConfigGenerator(
|
212
|
+
generator = TestConfigGenerator()
|
213
|
+
generator.create_all_test_configs()
|
296
214
|
|
297
|
-
|
298
|
-
|
299
|
-
if args.modifications:
|
300
|
-
modifications = json.loads(args.modifications)
|
301
|
-
else:
|
302
|
-
# Use predefined modifications
|
303
|
-
predefined = {
|
304
|
-
"http_simple": {"server.port": 8001, "ssl.enabled": False, "security.enabled": False},
|
305
|
-
"https_simple": {"server.port": 8003, "ssl.enabled": True},
|
306
|
-
"mtls_simple": {"server.port": 8005, "ssl.enabled": True, "ssl.verify_client": True},
|
307
|
-
}
|
308
|
-
modifications = predefined.get(args.config_name, {})
|
309
|
-
|
310
|
-
generator.create_config(args.config_name, modifications)
|
311
|
-
else:
|
312
|
-
# Create all test configurations
|
313
|
-
generator.create_all_test_configs()
|
215
|
+
print("\n🎉 All test configurations created successfully!")
|
216
|
+
print(f"📁 Output directory: {generator.output_dir}")
|
314
217
|
|
315
218
|
|
316
219
|
if __name__ == "__main__":
|
317
|
-
main()
|
220
|
+
main()
|