mcp-proxy-adapter 6.8.2__py3-none-any.whl → 6.9.1__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/config.py +208 -110
- mcp_proxy_adapter/core/config_validator.py +1077 -189
- mcp_proxy_adapter/core/errors.py +42 -0
- mcp_proxy_adapter/core/logging.py +16 -16
- mcp_proxy_adapter/examples/config_builder.py +192 -741
- mcp_proxy_adapter/examples/full_application/main.py +10 -2
- mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
- mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +221 -0
- mcp_proxy_adapter/examples/generate_config.py +61 -8
- mcp_proxy_adapter/examples/test_config.py +47 -2
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.8.2.dist-info → mcp_proxy_adapter-6.9.1.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.8.2.dist-info → mcp_proxy_adapter-6.9.1.dist-info}/RECORD +17 -14
- {mcp_proxy_adapter-6.8.2.dist-info → mcp_proxy_adapter-6.9.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.8.2.dist-info → mcp_proxy_adapter-6.9.1.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.8.2.dist-info → mcp_proxy_adapter-6.9.1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
"""
|
3
|
-
|
4
|
-
|
3
|
+
Simple Configuration Generator for MCP Proxy Adapter
|
4
|
+
Generates a complete configuration with HTTP protocol and all restrictions disabled.
|
5
5
|
|
6
6
|
Author: Vasiliy Zdanovskiy
|
7
7
|
email: vasilyvz@gmail.com
|
@@ -9,758 +9,209 @@ email: vasilyvz@gmail.com
|
|
9
9
|
|
10
10
|
import json
|
11
11
|
import uuid
|
12
|
-
|
13
|
-
from
|
12
|
+
import argparse
|
13
|
+
from pathlib import Path
|
14
|
+
from typing import Dict, Any
|
14
15
|
|
15
16
|
|
16
|
-
|
17
|
-
"""Supported protocols."""
|
18
|
-
HTTP = "http"
|
19
|
-
HTTPS = "https"
|
20
|
-
MTLS = "mtls"
|
21
|
-
|
22
|
-
|
23
|
-
class AuthMethod(Enum):
|
24
|
-
"""Authentication methods."""
|
25
|
-
NONE = "none"
|
26
|
-
TOKEN = "token"
|
27
|
-
TOKEN_ROLES = "token_roles"
|
28
|
-
CERTIFICATE = "certificate"
|
29
|
-
BASIC = "basic"
|
30
|
-
OAUTH2 = "oauth2"
|
31
|
-
JWT = "jwt"
|
32
|
-
|
33
|
-
|
34
|
-
class ConfigBuilder:
|
35
|
-
"""Enhanced configuration builder with full feature support."""
|
36
|
-
|
37
|
-
def __init__(self):
|
38
|
-
"""Initialize the configuration builder."""
|
39
|
-
self._reset_to_defaults()
|
40
|
-
|
41
|
-
def _reset_to_defaults(self):
|
42
|
-
"""Reset configuration to default values with all sections."""
|
43
|
-
self.config = {
|
44
|
-
"uuid": str(uuid.uuid4()),
|
45
|
-
"server": {
|
46
|
-
"host": "0.0.0.0",
|
47
|
-
"port": 8000,
|
48
|
-
"protocol": "http",
|
49
|
-
"debug": False,
|
50
|
-
"log_level": "INFO"
|
51
|
-
},
|
52
|
-
"logging": {
|
53
|
-
"level": "INFO",
|
54
|
-
"file": None,
|
55
|
-
"log_dir": "./logs",
|
56
|
-
"log_file": "mcp_proxy_adapter.log",
|
57
|
-
"error_log_file": "mcp_proxy_adapter_error.log",
|
58
|
-
"access_log_file": "mcp_proxy_adapter_access.log",
|
59
|
-
"max_file_size": "10MB",
|
60
|
-
"backup_count": 5,
|
61
|
-
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
62
|
-
"date_format": "%Y-%m-%d %H:%M:%S",
|
63
|
-
"console_output": True,
|
64
|
-
"file_output": True,
|
65
|
-
"json_format": False
|
66
|
-
},
|
67
|
-
"commands": {
|
68
|
-
"auto_discovery": True,
|
69
|
-
"commands_directory": "./commands",
|
70
|
-
"catalog_directory": "./catalog",
|
71
|
-
"plugin_servers": [],
|
72
|
-
"auto_install_dependencies": True,
|
73
|
-
"enabled_commands": ["health", "echo", "list", "help"],
|
74
|
-
"disabled_commands": [],
|
75
|
-
"custom_commands_path": "./commands"
|
76
|
-
},
|
77
|
-
"ssl": {
|
78
|
-
"enabled": False,
|
79
|
-
"mode": "https_only",
|
80
|
-
"cert_file": None,
|
81
|
-
"key_file": None,
|
82
|
-
"ca_cert": None,
|
83
|
-
"verify_client": False,
|
84
|
-
"client_cert_required": False,
|
85
|
-
"chk_hostname": False,
|
86
|
-
"cipher_suites": [
|
87
|
-
"TLS_AES_256_GCM_SHA384",
|
88
|
-
"TLS_CHACHA20_POLY1305_SHA256"
|
89
|
-
],
|
90
|
-
"min_tls_version": "TLSv1.2",
|
91
|
-
"max_tls_version": None,
|
92
|
-
"token_auth": {
|
93
|
-
"enabled": False,
|
94
|
-
"header_name": "Authorization",
|
95
|
-
"token_prefix": "Bearer",
|
96
|
-
"tokens_file": "tokens.json",
|
97
|
-
"token_expiry": 3600,
|
98
|
-
"jwt_secret": "",
|
99
|
-
"jwt_algorithm": "HS256"
|
100
|
-
}
|
101
|
-
},
|
102
|
-
"transport": {
|
103
|
-
"type": "http",
|
104
|
-
"port": None,
|
105
|
-
"ssl": {
|
106
|
-
"enabled": False,
|
107
|
-
"cert_file": None,
|
108
|
-
"key_file": None,
|
109
|
-
"ca_cert": None,
|
110
|
-
"verify_client": False,
|
111
|
-
"client_cert_required": False
|
112
|
-
}
|
113
|
-
},
|
114
|
-
"proxy_registration": {
|
115
|
-
"enabled": False,
|
116
|
-
"proxy_url": "http://localhost:3004",
|
117
|
-
"server_id": "mcp_proxy_adapter",
|
118
|
-
"server_name": "MCP Proxy Adapter",
|
119
|
-
"description": "JSON-RPC API for interacting with MCP Proxy",
|
120
|
-
"version": "6.6.9",
|
121
|
-
"registration_timeout": 30,
|
122
|
-
"retry_attempts": 3,
|
123
|
-
"retry_delay": 5,
|
124
|
-
"auto_register_on_startup": True,
|
125
|
-
"auto_unregister_on_shutdown": True,
|
126
|
-
"auth_method": "none",
|
127
|
-
"server_url": None,
|
128
|
-
"fallback_proxy_url": None,
|
129
|
-
"public_host": None,
|
130
|
-
"public_port": None,
|
131
|
-
"protocol": None,
|
132
|
-
"certificate": {
|
133
|
-
"cert_file": None,
|
134
|
-
"key_file": None
|
135
|
-
},
|
136
|
-
"token": {
|
137
|
-
"token": None
|
138
|
-
},
|
139
|
-
"api_key": {
|
140
|
-
"key": None
|
141
|
-
},
|
142
|
-
"ssl": {
|
143
|
-
"ca_cert": None,
|
144
|
-
"verify_mode": "CERT_REQUIRED"
|
145
|
-
},
|
146
|
-
"heartbeat": {
|
147
|
-
"enabled": True,
|
148
|
-
"interval": 30,
|
149
|
-
"timeout": 10,
|
150
|
-
"retry_attempts": 3,
|
151
|
-
"retry_delay": 5
|
152
|
-
},
|
153
|
-
"proxy_info": {
|
154
|
-
"name": "mcp_proxy_adapter",
|
155
|
-
"description": "MCP Proxy Adapter",
|
156
|
-
"version": "6.6.9",
|
157
|
-
"capabilities": ["jsonrpc", "rest", "security"],
|
158
|
-
"endpoints": {
|
159
|
-
"jsonrpc": "/api/jsonrpc",
|
160
|
-
"rest": "/cmd",
|
161
|
-
"health": "/health"
|
162
|
-
}
|
163
|
-
}
|
164
|
-
},
|
165
|
-
"debug": {
|
166
|
-
"enabled": False,
|
167
|
-
"level": "WARNING",
|
168
|
-
"log_level": "DEBUG",
|
169
|
-
"trace_requests": False,
|
170
|
-
"trace_responses": False
|
171
|
-
},
|
172
|
-
"security": {
|
173
|
-
"framework": "mcp_security_framework",
|
174
|
-
"enabled": False,
|
175
|
-
"debug": False,
|
176
|
-
"environment": "dev",
|
177
|
-
"version": "1.0.0",
|
178
|
-
"tokens": {
|
179
|
-
"admin": "admin-secret-key",
|
180
|
-
"user": "user-secret-key",
|
181
|
-
"readonly": "readonly-secret-key"
|
182
|
-
},
|
183
|
-
"roles": {
|
184
|
-
"admin": ["read", "write", "delete", "admin"],
|
185
|
-
"user": ["read", "write"],
|
186
|
-
"readonly": ["read"]
|
187
|
-
},
|
188
|
-
"roles_file": None,
|
189
|
-
"auth": {
|
190
|
-
"enabled": False,
|
191
|
-
"methods": ["api_key"],
|
192
|
-
"api_keys": {},
|
193
|
-
"user_roles": {},
|
194
|
-
"jwt_secret": "",
|
195
|
-
"jwt_algorithm": "HS256",
|
196
|
-
"jwt_expiry_hours": 24,
|
197
|
-
"certificate_auth": False,
|
198
|
-
"certificate_roles_oid": "1.3.6.1.4.1.99999.1.1",
|
199
|
-
"certificate_permissions_oid": "1.3.6.1.4.1.99999.1.2",
|
200
|
-
"basic_auth": False,
|
201
|
-
"oauth2_config": None,
|
202
|
-
"public_paths": ["/health", "/docs", "/openapi.json"],
|
203
|
-
"security_headers": None
|
204
|
-
},
|
205
|
-
"ssl": {
|
206
|
-
"enabled": False,
|
207
|
-
"cert_file": None,
|
208
|
-
"key_file": None,
|
209
|
-
"ca_cert_file": None,
|
210
|
-
"client_cert_file": None,
|
211
|
-
"client_key_file": None,
|
212
|
-
"verify_mode": "CERT_NONE",
|
213
|
-
"min_tls_version": "TLSv1.2",
|
214
|
-
"max_tls_version": None,
|
215
|
-
"cipher_suite": None,
|
216
|
-
"check_hostname": True,
|
217
|
-
"check_expiry": True,
|
218
|
-
"expiry_warning_days": 30
|
219
|
-
},
|
220
|
-
"certificates": {
|
221
|
-
"enabled": False,
|
222
|
-
"ca_cert_path": None,
|
223
|
-
"ca_key_path": None,
|
224
|
-
"cert_storage_path": "./certs",
|
225
|
-
"key_storage_path": "./keys",
|
226
|
-
"default_validity_days": 365,
|
227
|
-
"key_size": 2048,
|
228
|
-
"hash_algorithm": "sha256",
|
229
|
-
"crl_enabled": False,
|
230
|
-
"crl_path": None,
|
231
|
-
"crl_url": None,
|
232
|
-
"crl_validity_days": 30,
|
233
|
-
"auto_renewal": False,
|
234
|
-
"renewal_threshold_days": 30
|
235
|
-
},
|
236
|
-
"permissions": {
|
237
|
-
"enabled": False,
|
238
|
-
"roles_file": None,
|
239
|
-
"default_role": "guest",
|
240
|
-
"admin_role": "admin",
|
241
|
-
"role_hierarchy": {},
|
242
|
-
"permission_cache_enabled": False,
|
243
|
-
"permission_cache_ttl": 300,
|
244
|
-
"wildcard_permissions": False,
|
245
|
-
"strict_mode": False,
|
246
|
-
"roles": None
|
247
|
-
},
|
248
|
-
"rate_limit": {
|
249
|
-
"enabled": False,
|
250
|
-
"default_requests_per_minute": 60,
|
251
|
-
"default_requests_per_hour": 1000,
|
252
|
-
"burst_limit": 2,
|
253
|
-
"window_size_seconds": 60,
|
254
|
-
"storage_backend": "memory",
|
255
|
-
"redis_config": None,
|
256
|
-
"cleanup_interval": 300,
|
257
|
-
"exempt_paths": ["/health", "/docs", "/openapi.json"],
|
258
|
-
"exempt_roles": ["admin"]
|
259
|
-
},
|
260
|
-
"logging": {
|
261
|
-
"enabled": True,
|
262
|
-
"level": "INFO",
|
263
|
-
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
264
|
-
"date_format": "%Y-%m-%d %H:%M:%S",
|
265
|
-
"file_path": None,
|
266
|
-
"max_file_size": 10,
|
267
|
-
"backup_count": 5,
|
268
|
-
"console_output": True,
|
269
|
-
"json_format": False,
|
270
|
-
"include_timestamp": True,
|
271
|
-
"include_level": True,
|
272
|
-
"include_module": True
|
273
|
-
}
|
274
|
-
},
|
275
|
-
"roles": {
|
276
|
-
"enabled": False,
|
277
|
-
"config_file": None,
|
278
|
-
"default_policy": {
|
279
|
-
"deny_by_default": False,
|
280
|
-
"require_role_match": False,
|
281
|
-
"case_sensitive": False,
|
282
|
-
"allow_wildcard": False
|
283
|
-
},
|
284
|
-
"auto_load": False,
|
285
|
-
"validation_enabled": False
|
286
|
-
},
|
287
|
-
"protocols": {
|
288
|
-
"enabled": True,
|
289
|
-
"allowed_protocols": ["http", "jsonrpc"],
|
290
|
-
"default_protocol": "http",
|
291
|
-
"auto_discovery": True,
|
292
|
-
"protocol_handlers": {
|
293
|
-
"http": {
|
294
|
-
"enabled": True,
|
295
|
-
"port": None,
|
296
|
-
"ssl": False
|
297
|
-
},
|
298
|
-
"https": {
|
299
|
-
"enabled": False,
|
300
|
-
"port": None,
|
301
|
-
"ssl": True
|
302
|
-
},
|
303
|
-
"mtls": {
|
304
|
-
"enabled": False,
|
305
|
-
"port": None,
|
306
|
-
"ssl": True,
|
307
|
-
"client_cert_required": True
|
308
|
-
}
|
309
|
-
}
|
310
|
-
}
|
311
|
-
}
|
312
|
-
|
313
|
-
def set_protocol(self, protocol: Protocol, cert_dir: str = "./certs", key_dir: str = "./keys"):
|
314
|
-
"""Set protocol configuration (HTTP, HTTPS, or mTLS)."""
|
315
|
-
self.config["server"]["protocol"] = protocol.value
|
316
|
-
|
317
|
-
# Set registration protocol to match server protocol
|
318
|
-
self.config["proxy_registration"]["protocol"] = protocol.value
|
319
|
-
|
320
|
-
# Update protocol handlers
|
321
|
-
for handler_name in self.config["protocols"]["protocol_handlers"]:
|
322
|
-
self.config["protocols"]["protocol_handlers"][handler_name]["enabled"] = False
|
323
|
-
|
324
|
-
if protocol == Protocol.HTTP:
|
325
|
-
# HTTP - no SSL, no client verification
|
326
|
-
self.config["transport"]["ssl"]["verify_client"] = False
|
327
|
-
self.config["transport"]["ssl"]["enabled"] = False
|
328
|
-
self.config["ssl"]["enabled"] = False
|
329
|
-
self.config["ssl"]["verify_client"] = False
|
330
|
-
self.config["ssl"]["chk_hostname"] = False
|
331
|
-
self.config["protocols"]["protocol_handlers"]["http"]["enabled"] = True
|
332
|
-
self.config["protocols"]["allowed_protocols"] = ["http"]
|
333
|
-
self.config["protocols"]["default_protocol"] = "http"
|
334
|
-
|
335
|
-
elif protocol == Protocol.HTTPS:
|
336
|
-
# HTTPS - SSL enabled, no client verification
|
337
|
-
self.config["transport"]["ssl"]["verify_client"] = False
|
338
|
-
self.config["transport"]["ssl"]["enabled"] = True
|
339
|
-
self.config["ssl"]["enabled"] = True
|
340
|
-
self.config["ssl"]["verify_client"] = False
|
341
|
-
self.config["ssl"]["chk_hostname"] = True
|
342
|
-
self.config["ssl"]["mode"] = "https_only"
|
343
|
-
self.config["protocols"]["protocol_handlers"]["https"]["enabled"] = True
|
344
|
-
self.config["protocols"]["allowed_protocols"] = ["https"]
|
345
|
-
self.config["protocols"]["default_protocol"] = "https"
|
346
|
-
|
347
|
-
elif protocol == Protocol.MTLS:
|
348
|
-
# mTLS - SSL enabled, client verification required
|
349
|
-
self.config["transport"]["ssl"]["verify_client"] = True
|
350
|
-
self.config["transport"]["ssl"]["enabled"] = True
|
351
|
-
self.config["ssl"]["enabled"] = True
|
352
|
-
self.config["ssl"]["verify_client"] = True
|
353
|
-
self.config["ssl"]["chk_hostname"] = True
|
354
|
-
self.config["ssl"]["mode"] = "mtls"
|
355
|
-
self.config["ssl"]["client_cert_required"] = True
|
356
|
-
self.config["protocols"]["protocol_handlers"]["mtls"]["enabled"] = True
|
357
|
-
self.config["protocols"]["allowed_protocols"] = ["mtls"]
|
358
|
-
self.config["protocols"]["default_protocol"] = "mtls"
|
359
|
-
|
360
|
-
return self
|
361
|
-
|
362
|
-
def set_auth(self, auth_method: AuthMethod, api_keys: Optional[Dict[str, str]] = None, roles: Optional[Dict[str, List[str]]] = None):
|
363
|
-
"""Set authentication configuration."""
|
364
|
-
if auth_method == AuthMethod.NONE:
|
365
|
-
self.config["security"]["enabled"] = False
|
366
|
-
self.config["security"]["auth"]["enabled"] = False
|
367
|
-
self.config["security"]["auth"]["methods"] = []
|
368
|
-
self.config["security"]["tokens"] = {}
|
369
|
-
self.config["security"]["roles"] = {}
|
370
|
-
self.config["security"]["roles_file"] = None
|
371
|
-
|
372
|
-
elif auth_method == AuthMethod.TOKEN:
|
373
|
-
self.config["security"]["enabled"] = True
|
374
|
-
self.config["security"]["auth"]["enabled"] = True
|
375
|
-
self.config["security"]["auth"]["methods"] = ["api_key"]
|
376
|
-
self.config["security"]["tokens"] = api_keys or {
|
377
|
-
"admin": "admin-secret-key",
|
378
|
-
"user": "user-secret-key"
|
379
|
-
}
|
380
|
-
self.config["security"]["roles"] = roles or {
|
381
|
-
"admin": ["read", "write", "delete", "admin"],
|
382
|
-
"user": ["read", "write"]
|
383
|
-
}
|
384
|
-
self.config["security"]["roles_file"] = None
|
385
|
-
|
386
|
-
elif auth_method == AuthMethod.TOKEN_ROLES:
|
387
|
-
self.config["security"]["enabled"] = True
|
388
|
-
self.config["security"]["auth"]["enabled"] = True
|
389
|
-
self.config["security"]["auth"]["methods"] = ["api_key"]
|
390
|
-
self.config["security"]["tokens"] = api_keys or {
|
391
|
-
"admin": "admin-secret-key",
|
392
|
-
"user": "user-secret-key",
|
393
|
-
"readonly": "readonly-secret-key"
|
394
|
-
}
|
395
|
-
self.config["security"]["roles"] = roles or {
|
396
|
-
"admin": ["read", "write", "delete", "admin"],
|
397
|
-
"user": ["read", "write"],
|
398
|
-
"readonly": ["read"]
|
399
|
-
}
|
400
|
-
self.config["security"]["roles_file"] = "configs/roles.json"
|
401
|
-
self.config["roles"]["enabled"] = True
|
402
|
-
self.config["roles"]["config_file"] = "configs/roles.json"
|
403
|
-
|
404
|
-
elif auth_method == AuthMethod.CERTIFICATE:
|
405
|
-
self.config["security"]["enabled"] = True
|
406
|
-
self.config["security"]["auth"]["enabled"] = True
|
407
|
-
self.config["security"]["auth"]["methods"] = ["certificate"]
|
408
|
-
self.config["security"]["auth"]["certificate_auth"] = True
|
409
|
-
self.config["security"]["ssl"]["enabled"] = True
|
410
|
-
self.config["security"]["ssl"]["verify_mode"] = "CERT_REQUIRED"
|
411
|
-
|
412
|
-
elif auth_method == AuthMethod.BASIC:
|
413
|
-
self.config["security"]["enabled"] = True
|
414
|
-
self.config["security"]["auth"]["enabled"] = True
|
415
|
-
self.config["security"]["auth"]["methods"] = ["basic"]
|
416
|
-
self.config["security"]["auth"]["basic_auth"] = True
|
417
|
-
|
418
|
-
elif auth_method == AuthMethod.OAUTH2:
|
419
|
-
self.config["security"]["enabled"] = True
|
420
|
-
self.config["security"]["auth"]["enabled"] = True
|
421
|
-
self.config["security"]["auth"]["methods"] = ["oauth2"]
|
422
|
-
self.config["security"]["auth"]["oauth2_config"] = {}
|
423
|
-
|
424
|
-
elif auth_method == AuthMethod.JWT:
|
425
|
-
self.config["security"]["enabled"] = True
|
426
|
-
self.config["security"]["auth"]["enabled"] = True
|
427
|
-
self.config["security"]["auth"]["methods"] = ["jwt"]
|
428
|
-
self.config["security"]["auth"]["jwt_secret"] = "your-jwt-secret"
|
429
|
-
self.config["security"]["auth"]["jwt_algorithm"] = "HS256"
|
430
|
-
|
431
|
-
return self
|
432
|
-
|
433
|
-
def set_server(self, host: str = "0.0.0.0", port: int = 8000, debug: bool = False, log_level: str = "INFO"):
|
434
|
-
"""Set server configuration."""
|
435
|
-
self.config["server"]["host"] = host
|
436
|
-
self.config["server"]["port"] = port
|
437
|
-
self.config["server"]["debug"] = debug
|
438
|
-
self.config["server"]["log_level"] = log_level
|
439
|
-
return self
|
440
|
-
|
441
|
-
def set_logging(self, log_dir: str = "./logs", level: str = "INFO", console_output: bool = True, file_output: bool = True):
|
442
|
-
"""Set logging configuration."""
|
443
|
-
self.config["logging"]["log_dir"] = log_dir
|
444
|
-
self.config["logging"]["level"] = level
|
445
|
-
self.config["logging"]["console_output"] = console_output
|
446
|
-
self.config["logging"]["file_output"] = file_output
|
447
|
-
return self
|
448
|
-
|
449
|
-
def set_commands(self, enabled_commands: Optional[List[str]] = None, disabled_commands: Optional[List[str]] = None):
|
450
|
-
"""Set commands configuration."""
|
451
|
-
if enabled_commands:
|
452
|
-
self.config["commands"]["enabled_commands"] = enabled_commands
|
453
|
-
if disabled_commands:
|
454
|
-
self.config["commands"]["disabled_commands"] = disabled_commands
|
455
|
-
return self
|
456
|
-
|
457
|
-
def set_roles_file(self, roles_file: str):
|
458
|
-
"""Set roles file path."""
|
459
|
-
self.config["security"]["roles_file"] = roles_file
|
460
|
-
self.config["roles"]["config_file"] = roles_file
|
461
|
-
self.config["roles"]["enabled"] = True
|
462
|
-
return self
|
463
|
-
|
464
|
-
def set_proxy_registration(self, enabled: bool = True, proxy_url: str = "http://localhost:3004",
|
465
|
-
public_host: Optional[str] = None, public_port: Optional[int] = None,
|
466
|
-
server_id: str = "mcp_proxy_adapter", server_name: str = "MCP Proxy Adapter",
|
467
|
-
description: str = "JSON-RPC API for interacting with MCP Proxy",
|
468
|
-
auth_method: str = "none", cert_file: Optional[str] = None, key_file: Optional[str] = None):
|
469
|
-
"""Set proxy registration configuration."""
|
470
|
-
self.config["proxy_registration"]["enabled"] = enabled
|
471
|
-
self.config["proxy_registration"]["proxy_url"] = proxy_url
|
472
|
-
self.config["proxy_registration"]["public_host"] = public_host
|
473
|
-
self.config["proxy_registration"]["public_port"] = public_port
|
474
|
-
self.config["proxy_registration"]["server_id"] = server_id
|
475
|
-
self.config["proxy_registration"]["server_name"] = server_name
|
476
|
-
self.config["proxy_registration"]["description"] = description
|
477
|
-
self.config["proxy_registration"]["auth_method"] = auth_method
|
478
|
-
|
479
|
-
if cert_file:
|
480
|
-
self.config["proxy_registration"]["certificate"]["cert_file"] = cert_file
|
481
|
-
if key_file:
|
482
|
-
self.config["proxy_registration"]["certificate"]["key_file"] = key_file
|
483
|
-
|
484
|
-
# Set protocol to match server protocol if not explicitly set
|
485
|
-
if self.config["proxy_registration"]["protocol"] is None:
|
486
|
-
self.config["proxy_registration"]["protocol"] = self.config["server"]["protocol"]
|
487
|
-
|
488
|
-
return self
|
489
|
-
|
490
|
-
def enable_auto_registration(self, proxy_url: str = "http://localhost:3004",
|
491
|
-
server_id: str = "mcp_proxy_adapter",
|
492
|
-
server_name: str = "MCP Proxy Adapter",
|
493
|
-
description: str = "JSON-RPC API for interacting with MCP Proxy",
|
494
|
-
auth_method: str = "none"):
|
495
|
-
"""
|
496
|
-
Enable automatic proxy registration with auto-determined parameters.
|
497
|
-
|
498
|
-
This method enables registration with automatic determination of:
|
499
|
-
- public_host: from hostname (if server.host is 0.0.0.0/127.0.0.1) or server.host
|
500
|
-
- public_port: from server.port
|
501
|
-
- protocol: from server.protocol
|
502
|
-
|
503
|
-
Args:
|
504
|
-
proxy_url: URL of the proxy server
|
505
|
-
server_id: Unique identifier for this server
|
506
|
-
server_name: Human-readable name for this server
|
507
|
-
description: Description of this server
|
508
|
-
auth_method: Authentication method for proxy registration
|
509
|
-
"""
|
510
|
-
self.config["proxy_registration"]["enabled"] = True
|
511
|
-
self.config["proxy_registration"]["proxy_url"] = proxy_url
|
512
|
-
self.config["proxy_registration"]["public_host"] = None # Auto-determined
|
513
|
-
self.config["proxy_registration"]["public_port"] = None # Auto-determined
|
514
|
-
self.config["proxy_registration"]["protocol"] = None # Auto-determined
|
515
|
-
self.config["proxy_registration"]["server_id"] = server_id
|
516
|
-
self.config["proxy_registration"]["server_name"] = server_name
|
517
|
-
self.config["proxy_registration"]["description"] = description
|
518
|
-
self.config["proxy_registration"]["auth_method"] = auth_method
|
519
|
-
|
520
|
-
return self
|
521
|
-
|
522
|
-
def set_ssl_certificates(self, cert_file: str, key_file: str, ca_cert: Optional[str] = None):
|
523
|
-
"""Set SSL certificate paths."""
|
524
|
-
self.config["ssl"]["cert_file"] = cert_file
|
525
|
-
self.config["ssl"]["key_file"] = key_file
|
526
|
-
if ca_cert:
|
527
|
-
self.config["ssl"]["ca_cert"] = ca_cert
|
528
|
-
return self
|
529
|
-
|
530
|
-
def set_debug(self, enabled: bool = True, log_level: str = "DEBUG"):
|
531
|
-
"""Set debug configuration."""
|
532
|
-
self.config["debug"]["enabled"] = enabled
|
533
|
-
self.config["debug"]["log_level"] = log_level
|
534
|
-
return self
|
535
|
-
|
536
|
-
def build(self) -> Dict[str, Any]:
|
537
|
-
"""Build and return the configuration."""
|
538
|
-
return self.config.copy()
|
539
|
-
|
540
|
-
def save(self, file_path: str) -> None:
|
541
|
-
"""Save configuration to file."""
|
542
|
-
with open(file_path, 'w', encoding='utf-8') as f:
|
543
|
-
json.dump(self.config, f, indent=2, ensure_ascii=False)
|
544
|
-
|
545
|
-
|
546
|
-
class ConfigFactory:
|
547
|
-
"""Factory for creating common configurations."""
|
548
|
-
|
549
|
-
@staticmethod
|
550
|
-
def create_http_config(port: int = 8000) -> Dict[str, Any]:
|
551
|
-
"""Create HTTP configuration."""
|
552
|
-
return (ConfigBuilder()
|
553
|
-
.set_protocol(Protocol.HTTP)
|
554
|
-
.set_server(port=port)
|
555
|
-
.build())
|
556
|
-
|
557
|
-
@staticmethod
|
558
|
-
def create_http_token_config(port: int = 8001) -> Dict[str, Any]:
|
559
|
-
"""Create HTTP with token authentication configuration."""
|
560
|
-
return (ConfigBuilder()
|
561
|
-
.set_protocol(Protocol.HTTP)
|
562
|
-
.set_auth(AuthMethod.TOKEN)
|
563
|
-
.set_server(port=port)
|
564
|
-
.build())
|
565
|
-
|
566
|
-
@staticmethod
|
567
|
-
def create_http_token_roles_config(port: int = 8002) -> Dict[str, Any]:
|
568
|
-
"""Create HTTP with token and roles configuration."""
|
569
|
-
return (ConfigBuilder()
|
570
|
-
.set_protocol(Protocol.HTTP)
|
571
|
-
.set_auth(AuthMethod.TOKEN_ROLES)
|
572
|
-
.set_server(port=port)
|
573
|
-
.build())
|
574
|
-
|
575
|
-
@staticmethod
|
576
|
-
def create_https_config(port: int = 8003) -> Dict[str, Any]:
|
577
|
-
"""Create HTTPS configuration."""
|
578
|
-
return (ConfigBuilder()
|
579
|
-
.set_protocol(Protocol.HTTPS)
|
580
|
-
.set_server(port=port)
|
581
|
-
.build())
|
582
|
-
|
583
|
-
@staticmethod
|
584
|
-
def create_https_token_config(port: int = 8004) -> Dict[str, Any]:
|
585
|
-
"""Create HTTPS with token authentication configuration."""
|
586
|
-
return (ConfigBuilder()
|
587
|
-
.set_protocol(Protocol.HTTPS)
|
588
|
-
.set_auth(AuthMethod.TOKEN)
|
589
|
-
.set_server(port=port)
|
590
|
-
.build())
|
591
|
-
|
592
|
-
@staticmethod
|
593
|
-
def create_https_token_roles_config(port: int = 8005) -> Dict[str, Any]:
|
594
|
-
"""Create HTTPS with token and roles configuration."""
|
595
|
-
return (ConfigBuilder()
|
596
|
-
.set_protocol(Protocol.HTTPS)
|
597
|
-
.set_auth(AuthMethod.TOKEN_ROLES)
|
598
|
-
.set_server(port=port)
|
599
|
-
.build())
|
600
|
-
|
601
|
-
@staticmethod
|
602
|
-
def create_mtls_config(port: int = 8006) -> Dict[str, Any]:
|
603
|
-
"""Create mTLS configuration."""
|
604
|
-
return (ConfigBuilder()
|
605
|
-
.set_protocol(Protocol.MTLS)
|
606
|
-
.set_server(port=port)
|
607
|
-
.build())
|
608
|
-
|
609
|
-
@staticmethod
|
610
|
-
def create_mtls_token_config(port: int = 8007) -> Dict[str, Any]:
|
611
|
-
"""Create mTLS with token authentication configuration."""
|
612
|
-
return (ConfigBuilder()
|
613
|
-
.set_protocol(Protocol.MTLS)
|
614
|
-
.set_auth(AuthMethod.TOKEN)
|
615
|
-
.set_server(port=port)
|
616
|
-
.build())
|
617
|
-
|
618
|
-
@staticmethod
|
619
|
-
def create_mtls_token_roles_config(port: int = 8008) -> Dict[str, Any]:
|
620
|
-
"""Create mTLS with token and roles configuration."""
|
621
|
-
return (ConfigBuilder()
|
622
|
-
.set_protocol(Protocol.MTLS)
|
623
|
-
.set_auth(AuthMethod.TOKEN_ROLES)
|
624
|
-
.set_server(port=port)
|
625
|
-
.build())
|
626
|
-
|
627
|
-
@staticmethod
|
628
|
-
def create_mtls_certificate_config(port: int = 8009) -> Dict[str, Any]:
|
629
|
-
"""Create mTLS with certificate authentication configuration."""
|
630
|
-
return (ConfigBuilder()
|
631
|
-
.set_protocol(Protocol.MTLS)
|
632
|
-
.set_auth(AuthMethod.CERTIFICATE)
|
633
|
-
.set_server(port=port)
|
634
|
-
.build())
|
635
|
-
|
636
|
-
@staticmethod
|
637
|
-
def create_http_with_proxy_config(port: int = 8010, proxy_url: str = "http://localhost:3004") -> Dict[str, Any]:
|
638
|
-
"""Create HTTP configuration with proxy registration."""
|
639
|
-
return (ConfigBuilder()
|
640
|
-
.set_protocol(Protocol.HTTP)
|
641
|
-
.set_server(port=port)
|
642
|
-
.set_proxy_registration(proxy_url=proxy_url)
|
643
|
-
.build())
|
644
|
-
|
645
|
-
@staticmethod
|
646
|
-
def create_https_with_proxy_config(port: int = 8011, proxy_url: str = "https://localhost:3004") -> Dict[str, Any]:
|
647
|
-
"""Create HTTPS configuration with proxy registration."""
|
648
|
-
return (ConfigBuilder()
|
649
|
-
.set_protocol(Protocol.HTTPS)
|
650
|
-
.set_server(port=port)
|
651
|
-
.set_proxy_registration(proxy_url=proxy_url)
|
652
|
-
.build())
|
653
|
-
|
654
|
-
@staticmethod
|
655
|
-
def create_mtls_with_proxy_config(port: int = 8012, proxy_url: str = "https://localhost:3004") -> Dict[str, Any]:
|
656
|
-
"""Create mTLS configuration with proxy registration."""
|
657
|
-
return (ConfigBuilder()
|
658
|
-
.set_protocol(Protocol.MTLS)
|
659
|
-
.set_server(port=port)
|
660
|
-
.set_proxy_registration(proxy_url=proxy_url)
|
661
|
-
.build())
|
662
|
-
|
663
|
-
@staticmethod
|
664
|
-
def create_http_with_auto_registration(port: int = 8013, proxy_url: str = "http://localhost:3004",
|
665
|
-
server_id: str = "mcp_proxy_adapter") -> Dict[str, Any]:
|
666
|
-
"""Create HTTP configuration with automatic proxy registration."""
|
667
|
-
return (ConfigBuilder()
|
668
|
-
.set_protocol(Protocol.HTTP)
|
669
|
-
.set_server(port=port)
|
670
|
-
.enable_auto_registration(proxy_url=proxy_url, server_id=server_id)
|
671
|
-
.build())
|
672
|
-
|
673
|
-
@staticmethod
|
674
|
-
def create_https_with_auto_registration(port: int = 8014, proxy_url: str = "https://localhost:3004",
|
675
|
-
server_id: str = "mcp_proxy_adapter") -> Dict[str, Any]:
|
676
|
-
"""Create HTTPS configuration with automatic proxy registration."""
|
677
|
-
return (ConfigBuilder()
|
678
|
-
.set_protocol(Protocol.HTTPS)
|
679
|
-
.set_server(port=port)
|
680
|
-
.enable_auto_registration(proxy_url=proxy_url, server_id=server_id)
|
681
|
-
.build())
|
682
|
-
|
683
|
-
@staticmethod
|
684
|
-
def create_mtls_with_auto_registration(port: int = 8015, proxy_url: str = "https://localhost:3004",
|
685
|
-
server_id: str = "mcp_proxy_adapter") -> Dict[str, Any]:
|
686
|
-
"""Create mTLS configuration with automatic proxy registration."""
|
687
|
-
return (ConfigBuilder()
|
688
|
-
.set_protocol(Protocol.MTLS)
|
689
|
-
.set_server(port=port)
|
690
|
-
.enable_auto_registration(proxy_url=proxy_url, server_id=server_id)
|
691
|
-
.build())
|
692
|
-
|
693
|
-
@staticmethod
|
694
|
-
def create_full_featured_config(port: int = 8020) -> Dict[str, Any]:
|
695
|
-
"""Create full-featured configuration with all options enabled."""
|
696
|
-
return (ConfigBuilder()
|
697
|
-
.set_protocol(Protocol.MTLS)
|
698
|
-
.set_auth(AuthMethod.TOKEN_ROLES)
|
699
|
-
.set_server(port=port)
|
700
|
-
.enable_auto_registration(
|
701
|
-
proxy_url="https://mcp-proxy:3004",
|
702
|
-
server_id="full-featured-server",
|
703
|
-
server_name="Full Featured Server",
|
704
|
-
description="Server with all features enabled"
|
705
|
-
)
|
706
|
-
.set_ssl_certificates(
|
707
|
-
cert_file="./certs/server.crt",
|
708
|
-
key_file="./keys/server.key",
|
709
|
-
ca_cert="./certs/ca.crt"
|
710
|
-
)
|
711
|
-
.set_debug(enabled=True)
|
712
|
-
.build())
|
713
|
-
|
714
|
-
|
715
|
-
def create_config_from_flags(protocol: str, token: bool = False, roles: bool = False, port: int = 8000,
|
716
|
-
proxy_registration: bool = False, proxy_url: str = "http://localhost:3004",
|
717
|
-
auto_registration: bool = False, server_id: str = "mcp_proxy_adapter") -> Dict[str, Any]:
|
17
|
+
def generate_complete_config(host: str = "0.0.0.0", port: int = 8000) -> Dict[str, Any]:
|
718
18
|
"""
|
719
|
-
|
19
|
+
Generate a complete configuration with all required sections.
|
20
|
+
HTTP protocol with all security features disabled.
|
720
21
|
|
721
22
|
Args:
|
722
|
-
|
723
|
-
token: Enable token authentication
|
724
|
-
roles: Enable role-based access control
|
23
|
+
host: Server host
|
725
24
|
port: Server port
|
726
|
-
proxy_registration: Enable proxy registration with manual settings
|
727
|
-
proxy_url: Proxy URL for registration
|
728
|
-
auto_registration: Enable automatic proxy registration (auto-determined parameters)
|
729
|
-
server_id: Server ID for registration
|
730
25
|
|
731
26
|
Returns:
|
732
|
-
|
27
|
+
Complete configuration dictionary
|
733
28
|
"""
|
734
|
-
|
735
|
-
"
|
736
|
-
"
|
737
|
-
|
29
|
+
return {
|
30
|
+
"uuid": str(uuid.uuid4()),
|
31
|
+
"server": {
|
32
|
+
"host": host,
|
33
|
+
"port": port,
|
34
|
+
"protocol": "http",
|
35
|
+
"debug": False,
|
36
|
+
"log_level": "INFO"
|
37
|
+
},
|
38
|
+
"logging": {
|
39
|
+
"level": "INFO",
|
40
|
+
"file": None,
|
41
|
+
"log_dir": "./logs",
|
42
|
+
"log_file": "mcp_proxy_adapter.log",
|
43
|
+
"error_log_file": "mcp_proxy_adapter_error.log",
|
44
|
+
"access_log_file": "mcp_proxy_adapter_access.log",
|
45
|
+
"max_file_size": "10MB",
|
46
|
+
"backup_count": 5,
|
47
|
+
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
48
|
+
"date_format": "%Y-%m-%d %H:%M:%S",
|
49
|
+
"console_output": True,
|
50
|
+
"file_output": True
|
51
|
+
},
|
52
|
+
"commands": {
|
53
|
+
"auto_discovery": True,
|
54
|
+
"commands_directory": "./commands",
|
55
|
+
"catalog_directory": "./catalog",
|
56
|
+
"plugin_servers": [],
|
57
|
+
"auto_install_dependencies": True,
|
58
|
+
"enabled_commands": ["health", "echo", "list", "help"],
|
59
|
+
"disabled_commands": [],
|
60
|
+
"custom_commands_path": "./commands"
|
61
|
+
},
|
62
|
+
"transport": {
|
63
|
+
"type": "http",
|
64
|
+
"port": None,
|
65
|
+
"verify_client": False,
|
66
|
+
"chk_hostname": False
|
67
|
+
},
|
68
|
+
"proxy_registration": {
|
69
|
+
"enabled": False,
|
70
|
+
"proxy_url": "http://localhost:3004",
|
71
|
+
"server_id": "mcp_proxy_adapter",
|
72
|
+
"server_name": "MCP Proxy Adapter",
|
73
|
+
"description": "JSON-RPC API for interacting with MCP Proxy",
|
74
|
+
"version": "6.2.33",
|
75
|
+
"registration_timeout": 30,
|
76
|
+
"retry_attempts": 3,
|
77
|
+
"retry_delay": 5,
|
78
|
+
"auto_register_on_startup": True,
|
79
|
+
"auto_unregister_on_shutdown": True
|
80
|
+
},
|
81
|
+
"debug": {
|
82
|
+
"enabled": False,
|
83
|
+
"level": "WARNING"
|
84
|
+
},
|
85
|
+
"security": {
|
86
|
+
"enabled": False,
|
87
|
+
"tokens": {},
|
88
|
+
"roles": {},
|
89
|
+
"roles_file": None
|
90
|
+
},
|
91
|
+
"roles": {
|
92
|
+
"enabled": False,
|
93
|
+
"config_file": None,
|
94
|
+
"default_policy": {
|
95
|
+
"deny_by_default": False,
|
96
|
+
"require_role_match": False,
|
97
|
+
"case_sensitive": False,
|
98
|
+
"allow_wildcard": False
|
99
|
+
},
|
100
|
+
"auto_load": False,
|
101
|
+
"validation_enabled": False
|
102
|
+
}
|
738
103
|
}
|
104
|
+
|
105
|
+
|
106
|
+
def save_config(config: Dict[str, Any], output_file: str) -> None:
|
107
|
+
"""
|
108
|
+
Save configuration to file.
|
739
109
|
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
builder.set_auth(AuthMethod.TOKEN_ROLES)
|
747
|
-
elif token:
|
748
|
-
builder.set_auth(AuthMethod.TOKEN)
|
749
|
-
else:
|
750
|
-
builder.set_auth(AuthMethod.NONE)
|
110
|
+
Args:
|
111
|
+
config: Configuration dictionary
|
112
|
+
output_file: Output file path
|
113
|
+
"""
|
114
|
+
output_path = Path(output_file)
|
115
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
751
116
|
|
752
|
-
|
753
|
-
|
754
|
-
# Use automatic registration with auto-determined parameters
|
755
|
-
builder.enable_auto_registration(proxy_url=proxy_url, server_id=server_id)
|
756
|
-
elif proxy_registration:
|
757
|
-
# Use manual registration settings
|
758
|
-
builder.set_proxy_registration(proxy_url=proxy_url)
|
117
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
118
|
+
json.dump(config, f, indent=2, ensure_ascii=False)
|
759
119
|
|
760
|
-
|
120
|
+
print(f"✅ Configuration saved to: {output_path}")
|
121
|
+
|
122
|
+
|
123
|
+
def main():
|
124
|
+
"""Main function to generate configuration."""
|
125
|
+
parser = argparse.ArgumentParser(
|
126
|
+
description="Generate complete MCP Proxy Adapter configuration",
|
127
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
128
|
+
epilog="""
|
129
|
+
Examples:
|
130
|
+
python config_builder.py
|
131
|
+
python config_builder.py --host 127.0.0.1 --port 9000
|
132
|
+
python config_builder.py --output ./configs/my_config.json
|
133
|
+
"""
|
134
|
+
)
|
135
|
+
|
136
|
+
parser.add_argument(
|
137
|
+
"--host",
|
138
|
+
default="0.0.0.0",
|
139
|
+
help="Server host (default: 0.0.0.0)"
|
140
|
+
)
|
141
|
+
|
142
|
+
parser.add_argument(
|
143
|
+
"--port",
|
144
|
+
type=int,
|
145
|
+
default=8000,
|
146
|
+
help="Server port (default: 8000)"
|
147
|
+
)
|
148
|
+
|
149
|
+
parser.add_argument(
|
150
|
+
"--output",
|
151
|
+
default="config.json",
|
152
|
+
help="Output file path (default: config.json)"
|
153
|
+
)
|
154
|
+
|
155
|
+
parser.add_argument(
|
156
|
+
"--validate",
|
157
|
+
action="store_true",
|
158
|
+
help="Validate generated configuration"
|
159
|
+
)
|
160
|
+
|
161
|
+
args = parser.parse_args()
|
162
|
+
|
163
|
+
print("🔧 Generating MCP Proxy Adapter configuration...")
|
164
|
+
print(f" Host: {args.host}")
|
165
|
+
print(f" Port: {args.port}")
|
166
|
+
print(f" Protocol: HTTP")
|
167
|
+
print(f" Security: Disabled")
|
168
|
+
print(f" SSL: Disabled")
|
169
|
+
print(f" Roles: Disabled")
|
170
|
+
print()
|
171
|
+
|
172
|
+
# Generate configuration
|
173
|
+
config = generate_complete_config(args.host, args.port)
|
174
|
+
|
175
|
+
# Save configuration
|
176
|
+
save_config(config, args.output)
|
177
|
+
|
178
|
+
# Validate if requested
|
179
|
+
if args.validate:
|
180
|
+
print("\n🔍 Validating configuration...")
|
181
|
+
try:
|
182
|
+
from mcp_proxy_adapter.core.config_validator import ConfigValidator
|
183
|
+
|
184
|
+
validator = ConfigValidator()
|
185
|
+
validator.config_data = config
|
186
|
+
results = validator.validate_config()
|
187
|
+
|
188
|
+
if results:
|
189
|
+
print("⚠️ Validation issues found:")
|
190
|
+
for result in results:
|
191
|
+
level_symbol = {
|
192
|
+
"error": "❌",
|
193
|
+
"warning": "⚠️",
|
194
|
+
"info": "ℹ️"
|
195
|
+
}[result.level]
|
196
|
+
print(f" {level_symbol} {result.message}")
|
197
|
+
if result.suggestion:
|
198
|
+
print(f" Suggestion: {result.suggestion}")
|
199
|
+
else:
|
200
|
+
print("✅ Configuration validation passed!")
|
201
|
+
|
202
|
+
except ImportError:
|
203
|
+
print("⚠️ Configuration validation not available")
|
204
|
+
except Exception as e:
|
205
|
+
print(f"❌ Validation error: {e}")
|
206
|
+
|
207
|
+
print(f"\n📋 Configuration summary:")
|
208
|
+
print(f" - Server: {config['server']['host']}:{config['server']['port']}")
|
209
|
+
print(f" - Protocol: {config['server']['protocol']}")
|
210
|
+
print(f" - Security: {'Enabled' if config['security']['enabled'] else 'Disabled'}")
|
211
|
+
print(f" - SSL: {'Enabled' if config.get('ssl', {}).get('enabled', False) else 'Disabled'}")
|
212
|
+
print(f" - Roles: {'Enabled' if config['roles']['enabled'] else 'Disabled'}")
|
213
|
+
print(f" - Proxy Registration: {'Enabled' if config['proxy_registration']['enabled'] else 'Disabled'}")
|
761
214
|
|
762
215
|
|
763
216
|
if __name__ == "__main__":
|
764
|
-
|
765
|
-
config = create_config_from_flags("http", token=True, port=8001)
|
766
|
-
print(json.dumps(config, indent=2))
|
217
|
+
main()
|