mcp-proxy-adapter 6.2.25__py3-none-any.whl → 6.2.27__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.
@@ -7,14 +7,14 @@ email: vasilyvz@gmail.com
7
7
 
8
8
  import json
9
9
  import os
10
- from pathlib import Path
11
- from typing import Any, Dict, Optional
10
+ from typing import Any, Dict, Optional, List
12
11
 
13
12
 
14
13
  class Config:
15
14
  """
16
15
  Configuration management class for the microservice.
17
16
  Allows loading settings from configuration file and environment variables.
17
+ Supports optional features that can be enabled/disabled.
18
18
  """
19
19
 
20
20
  def __init__(self, config_path: Optional[str] = None):
@@ -22,7 +22,8 @@ class Config:
22
22
  Initialize configuration.
23
23
 
24
24
  Args:
25
- config_path: Path to configuration file. If not specified, "./config.json" is used.
25
+ config_path: Path to configuration file. If not specified,
26
+ "./config.json" is used.
26
27
  """
27
28
  self.config_path = config_path or "./config.json"
28
29
  self.config_data: Dict[str, Any] = {}
@@ -56,10 +57,13 @@ class Config:
56
57
  },
57
58
  "commands": {
58
59
  "auto_discovery": True,
59
- "commands_directory": "./commands", # Path to directory with command files
60
- "catalog_directory": "./catalog", # Path to command catalog directory
61
- "plugin_servers": [], # List of plugin server URLs
62
- "auto_install_dependencies": True # Automatically install plugin dependencies
60
+ "commands_directory": "./commands",
61
+ "catalog_directory": "./catalog",
62
+ "plugin_servers": [],
63
+ "auto_install_dependencies": True,
64
+ "enabled_commands": ["health", "echo", "list", "help"],
65
+ "disabled_commands": [],
66
+ "custom_commands_path": "./commands"
63
67
  },
64
68
  "ssl": {
65
69
  "enabled": False,
@@ -69,7 +73,10 @@ class Config:
69
73
  "ca_cert": None,
70
74
  "verify_client": False,
71
75
  "client_cert_required": False,
72
- "cipher_suites": ["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"],
76
+ "cipher_suites": [
77
+ "TLS_AES_256_GCM_SHA384",
78
+ "TLS_CHACHA20_POLY1305_SHA256"
79
+ ],
73
80
  "min_tls_version": "TLSv1.2",
74
81
  "max_tls_version": "1.3",
75
82
  "token_auth": {
@@ -118,12 +125,6 @@ class Config:
118
125
  "auto_register_on_startup": True,
119
126
  "auto_unregister_on_shutdown": True
120
127
  },
121
- "commands": {
122
- "auto_discovery": True,
123
- "enabled_commands": ["health", "echo", "list", "help"],
124
- "disabled_commands": [],
125
- "custom_commands_path": "./commands"
126
- },
127
128
  "debug": {
128
129
  "enabled": False,
129
130
  "level": "WARNING"
@@ -226,7 +227,7 @@ class Config:
226
227
  "auto_discovery": True
227
228
  }
228
229
  }
229
-
230
+
230
231
  # Try to load configuration from file
231
232
  if os.path.exists(self.config_path):
232
233
  try:
@@ -235,7 +236,7 @@ class Config:
235
236
  self._update_nested_dict(self.config_data, file_config)
236
237
  except Exception as e:
237
238
  print(f"Error loading config from {self.config_path}: {e}")
238
-
239
+
239
240
  # Load configuration from environment variables
240
241
  self._load_env_variables()
241
242
 
@@ -300,14 +301,14 @@ class Config:
300
301
  Configuration value
301
302
  """
302
303
  parts = key.split(".")
303
-
304
+
304
305
  # Get value from config
305
306
  value = self.config_data
306
307
  for part in parts:
307
308
  if not isinstance(value, dict) or part not in value:
308
309
  return default
309
310
  value = value[part]
310
-
311
+
311
312
  return value
312
313
 
313
314
  def get_all(self) -> Dict[str, Any]:
@@ -332,17 +333,17 @@ class Config:
332
333
  self.config_data[key] = value
333
334
  else:
334
335
  section = parts[0]
335
- param = ".".join(parts[1:])
336
-
336
+ param_key = ".".join(parts[1:])
337
+
337
338
  if section not in self.config_data:
338
339
  self.config_data[section] = {}
339
-
340
+
340
341
  current = self.config_data[section]
341
342
  for part in parts[1:-1]:
342
343
  if part not in current:
343
344
  current[part] = {}
344
345
  current = current[part]
345
-
346
+
346
347
  current[parts[-1]] = value
347
348
 
348
349
  def save(self, path: Optional[str] = None) -> None:
@@ -350,7 +351,8 @@ class Config:
350
351
  Save configuration to file.
351
352
 
352
353
  Args:
353
- path: Path to configuration file. If not specified, self.config_path is used.
354
+ path: Path to configuration file. If not specified,
355
+ self.config_path is used.
354
356
  """
355
357
  save_path = path or self.config_path
356
358
  with open(save_path, 'w', encoding='utf-8') as f:
@@ -374,6 +376,215 @@ class Config:
374
376
  d[k] = v
375
377
  return d
376
378
 
379
+ def enable_feature(self, feature: str) -> None:
380
+ """
381
+ Enable a specific feature in the configuration.
382
+
383
+ Args:
384
+ feature: Feature to enable (ssl, auth, roles, proxy_registration,
385
+ security)
386
+ """
387
+ if feature == "ssl":
388
+ self.set("ssl.enabled", True)
389
+ self.set("security.ssl.enabled", True)
390
+ elif feature == "auth":
391
+ self.set("security.auth.enabled", True)
392
+ elif feature == "roles":
393
+ self.set("security.permissions.enabled", True)
394
+ self.set("roles.enabled", True)
395
+ elif feature == "proxy_registration":
396
+ self.set("proxy_registration.enabled", True)
397
+ elif feature == "security":
398
+ self.set("security.enabled", True)
399
+ elif feature == "rate_limit":
400
+ self.set("security.rate_limit.enabled", True)
401
+ elif feature == "certificates":
402
+ self.set("security.certificates.enabled", True)
403
+ else:
404
+ raise ValueError(f"Unknown feature: {feature}")
405
+
406
+ def disable_feature(self, feature: str) -> None:
407
+ """
408
+ Disable a specific feature in the configuration.
409
+
410
+ Args:
411
+ feature: Feature to disable (ssl, auth, roles, proxy_registration,
412
+ security)
413
+ """
414
+ if feature == "ssl":
415
+ self.set("ssl.enabled", False)
416
+ self.set("security.ssl.enabled", False)
417
+ elif feature == "auth":
418
+ self.set("security.auth.enabled", False)
419
+ elif feature == "roles":
420
+ self.set("security.permissions.enabled", False)
421
+ self.set("roles.enabled", False)
422
+ elif feature == "proxy_registration":
423
+ self.set("proxy_registration.enabled", False)
424
+ elif feature == "security":
425
+ self.set("security.enabled", False)
426
+ elif feature == "rate_limit":
427
+ self.set("security.rate_limit.enabled", False)
428
+ elif feature == "certificates":
429
+ self.set("security.certificates.enabled", False)
430
+ else:
431
+ raise ValueError(f"Unknown feature: {feature}")
432
+
433
+ def is_feature_enabled(self, feature: str) -> bool:
434
+ """
435
+ Check if a specific feature is enabled.
436
+
437
+ Args:
438
+ feature: Feature to check (ssl, auth, roles, proxy_registration,
439
+ security)
440
+
441
+ Returns:
442
+ True if feature is enabled, False otherwise
443
+ """
444
+ if feature == "ssl":
445
+ return (self.get("ssl.enabled", False) or
446
+ self.get("security.ssl.enabled", False))
447
+ elif feature == "auth":
448
+ return self.get("security.auth.enabled", False)
449
+ elif feature == "roles":
450
+ return (self.get("security.permissions.enabled", False) or
451
+ self.get("roles.enabled", False))
452
+ elif feature == "proxy_registration":
453
+ return self.get("proxy_registration.enabled", False)
454
+ elif feature == "security":
455
+ return self.get("security.enabled", False)
456
+ elif feature == "rate_limit":
457
+ return self.get("security.rate_limit.enabled", False)
458
+ elif feature == "certificates":
459
+ return self.get("security.certificates.enabled", False)
460
+ else:
461
+ raise ValueError(f"Unknown feature: {feature}")
462
+
463
+ def get_enabled_features(self) -> List[str]:
464
+ """
465
+ Get list of all enabled features.
466
+
467
+ Returns:
468
+ List of enabled feature names
469
+ """
470
+ features = []
471
+ if self.is_feature_enabled("ssl"):
472
+ features.append("ssl")
473
+ if self.is_feature_enabled("auth"):
474
+ features.append("auth")
475
+ if self.is_feature_enabled("roles"):
476
+ features.append("roles")
477
+ if self.is_feature_enabled("proxy_registration"):
478
+ features.append("proxy_registration")
479
+ if self.is_feature_enabled("security"):
480
+ features.append("security")
481
+ if self.is_feature_enabled("rate_limit"):
482
+ features.append("rate_limit")
483
+ if self.is_feature_enabled("certificates"):
484
+ features.append("certificates")
485
+ return features
486
+
487
+ def configure_auth_mode(self, mode: str, **kwargs) -> None:
488
+ """
489
+ Configure authentication mode.
490
+
491
+ Args:
492
+ mode: Authentication mode (api_key, jwt, certificate, basic, oauth2)
493
+ **kwargs: Additional configuration parameters
494
+ """
495
+ if mode == "api_key":
496
+ self.set("security.auth.methods", ["api_key"])
497
+ if "api_keys" in kwargs:
498
+ self.set("security.auth.api_keys", kwargs["api_keys"])
499
+ elif mode == "jwt":
500
+ self.set("security.auth.methods", ["jwt"])
501
+ if "jwt_secret" in kwargs:
502
+ self.set("security.auth.jwt_secret", kwargs["jwt_secret"])
503
+ elif mode == "certificate":
504
+ self.set("security.auth.methods", ["certificate"])
505
+ self.set("security.auth.certificate_auth", True)
506
+ elif mode == "basic":
507
+ self.set("security.auth.methods", ["basic"])
508
+ self.set("security.auth.basic_auth", True)
509
+ elif mode == "oauth2":
510
+ self.set("security.auth.methods", ["oauth2"])
511
+ if "oauth2_config" in kwargs:
512
+ self.set("security.auth.oauth2_config", kwargs["oauth2_config"])
513
+ else:
514
+ raise ValueError(f"Unknown authentication mode: {mode}")
515
+
516
+ def configure_proxy_registration_mode(self, mode: str, **kwargs) -> None:
517
+ """
518
+ Configure proxy registration mode.
519
+
520
+ Args:
521
+ mode: Registration mode (token, certificate, api_key, none)
522
+ **kwargs: Additional configuration parameters
523
+ """
524
+ if mode == "none":
525
+ self.set("proxy_registration.enabled", False)
526
+ else:
527
+ self.set("proxy_registration.enabled", True)
528
+
529
+ if mode == "token":
530
+ self.set("proxy_registration.auth_method", "token")
531
+ if "token" in kwargs:
532
+ self.set("proxy_registration.token.token", kwargs["token"])
533
+ elif mode == "certificate":
534
+ self.set("proxy_registration.auth_method", "certificate")
535
+ if "cert_file" in kwargs:
536
+ self.set("proxy_registration.certificate.cert_file",
537
+ kwargs["cert_file"])
538
+ if "key_file" in kwargs:
539
+ self.set("proxy_registration.certificate.key_file",
540
+ kwargs["key_file"])
541
+ elif mode == "api_key":
542
+ self.set("proxy_registration.auth_method", "api_key")
543
+ if "key" in kwargs:
544
+ self.set("proxy_registration.api_key.key", kwargs["key"])
545
+
546
+ def create_minimal_config(self) -> Dict[str, Any]:
547
+ """
548
+ Create minimal configuration with only essential features.
549
+
550
+ Returns:
551
+ Minimal configuration dictionary
552
+ """
553
+ minimal_config = self.config_data.copy()
554
+
555
+ # Disable all optional features
556
+ minimal_config["ssl"]["enabled"] = False
557
+ minimal_config["security"]["enabled"] = False
558
+ minimal_config["security"]["auth"]["enabled"] = False
559
+ minimal_config["security"]["permissions"]["enabled"] = False
560
+ minimal_config["security"]["rate_limit"]["enabled"] = False
561
+ minimal_config["security"]["certificates"]["enabled"] = False
562
+ minimal_config["proxy_registration"]["enabled"] = False
563
+ minimal_config["roles"]["enabled"] = False
564
+
565
+ return minimal_config
566
+
567
+ def create_secure_config(self) -> Dict[str, Any]:
568
+ """
569
+ Create secure configuration with all security features enabled.
570
+
571
+ Returns:
572
+ Secure configuration dictionary
573
+ """
574
+ secure_config = self.config_data.copy()
575
+
576
+ # Enable all security features
577
+ secure_config["ssl"]["enabled"] = True
578
+ secure_config["security"]["enabled"] = True
579
+ secure_config["security"]["auth"]["enabled"] = True
580
+ secure_config["security"]["permissions"]["enabled"] = True
581
+ secure_config["security"]["rate_limit"]["enabled"] = True
582
+ secure_config["security"]["certificates"]["enabled"] = True
583
+ secure_config["proxy_registration"]["enabled"] = True
584
+ secure_config["roles"]["enabled"] = True
585
+
586
+ return secure_config
587
+
377
588
 
378
589
  # Singleton instance
379
590
  config = Config()
@@ -9,7 +9,11 @@ import json
9
9
  import os
10
10
  import argparse
11
11
  from typing import Dict, Any
12
- def generate_http_simple_config(port: int = 20000, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
12
+
13
+
14
+ def generate_http_simple_config(
15
+ port: int = 20000, certs_dir: str = "certs", keys_dir: str = "keys"
16
+ ) -> Dict[str, Any]:
13
17
  """Generate HTTP configuration without authorization."""
14
18
  return {
15
19
  "server": {"host": "127.0.0.1", "port": port},
@@ -23,13 +27,27 @@ def generate_http_simple_config(port: int = 20000, certs_dir: str = "certs", key
23
27
  "proxy_info": {
24
28
  "name": "mcp_example_server",
25
29
  "capabilities": ["jsonrpc", "rest", "proxy_registration"],
26
- "endpoints": {"jsonrpc": "/api/jsonrpc", "rest": "/cmd", "health": "/health"}
30
+ "endpoints": {
31
+ "jsonrpc": "/api/jsonrpc",
32
+ "rest": "/cmd",
33
+ "health": "/health"
34
+ }
27
35
  },
28
36
  "heartbeat": {"enabled": True, "interval": 30}
29
37
  },
30
- "protocols": {"enabled": True, "allowed_protocols": ["http"]}
38
+ "protocols": {
39
+ "enabled": True,
40
+ "allowed_protocols": ["http"]
41
+ }
31
42
  }
32
- def generate_http_token_config(port: int = 20001, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> Dict[str, Any]:
43
+
44
+
45
+ def generate_http_token_config(
46
+ port: int = 20001,
47
+ certs_dir: str = "certs",
48
+ keys_dir: str = "keys",
49
+ roles_file: str = "configs/roles.json"
50
+ ) -> Dict[str, Any]:
33
51
  """Generate HTTP configuration with token authorization."""
34
52
  return {
35
53
  "server": {"host": "127.0.0.1", "port": port},
@@ -59,9 +77,16 @@ def generate_http_token_config(port: int = 20001, certs_dir: str = "certs", keys
59
77
  "retry_delay": 5,
60
78
  "heartbeat": {"enabled": True, "interval": 30}
61
79
  },
62
- "protocols": {"enabled": True, "allowed_protocols": ["http"]}
80
+ "protocols": {
81
+ "enabled": True,
82
+ "allowed_protocols": ["http"]
83
+ }
63
84
  }
64
- def generate_https_simple_config(port: int = 20002, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
85
+
86
+
87
+ def generate_https_simple_config(
88
+ port: int = 20002, certs_dir: str = "certs", keys_dir: str = "keys"
89
+ ) -> Dict[str, Any]:
65
90
  """Generate HTTPS configuration without client certificate verification and authorization."""
66
91
  return {
67
92
  "server": {"host": "127.0.0.1", "port": port},
@@ -80,9 +105,16 @@ def generate_https_simple_config(port: int = 20002, certs_dir: str = "certs", ke
80
105
  "retry_delay": 5,
81
106
  "heartbeat": {"enabled": True, "interval": 30}
82
107
  },
83
- "protocols": {"enabled": True, "allowed_protocols": ["http", "https"]}
108
+ "protocols": {
109
+ "enabled": True,
110
+ "allowed_protocols": ["http", "https"]
111
+ }
84
112
  }
85
- def generate_https_token_config(port: int = 20003, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
113
+
114
+
115
+ def generate_https_token_config(
116
+ port: int = 20003, certs_dir: str = "certs", keys_dir: str = "keys"
117
+ ) -> Dict[str, Any]:
86
118
  """Generate HTTPS configuration without client certificate verification with token authorization."""
87
119
  return {
88
120
  "server": {"host": "127.0.0.1", "port": port},
@@ -115,9 +147,16 @@ def generate_https_token_config(port: int = 20003, certs_dir: str = "certs", key
115
147
  "retry_delay": 5,
116
148
  "heartbeat": {"enabled": True, "interval": 30}
117
149
  },
118
- "protocols": {"enabled": True, "allowed_protocols": ["http", "https"]}
150
+ "protocols": {
151
+ "enabled": True,
152
+ "allowed_protocols": ["http", "https"]
153
+ }
119
154
  }
120
- def generate_mtls_no_roles_config(port: int = 20004, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
155
+
156
+
157
+ def generate_mtls_no_roles_config(
158
+ port: int = 20004, certs_dir: str = "certs", keys_dir: str = "keys"
159
+ ) -> Dict[str, Any]:
121
160
  """Generate mTLS configuration without roles."""
122
161
  return {
123
162
  "server": {"host": "127.0.0.1", "port": port},
@@ -126,16 +165,30 @@ def generate_mtls_no_roles_config(port: int = 20004, certs_dir: str = "certs", k
126
165
  "cert_file": f"{certs_dir}/localhost_server.crt",
127
166
  "key_file": f"{keys_dir}/localhost_server.key",
128
167
  "ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
129
- "verify_client": True
168
+ "verify_client": True,
169
+ "client_cert_required": True
130
170
  },
131
171
  "security": {
132
172
  "enabled": True,
133
173
  "auth": {"enabled": True, "methods": ["certificate"]},
134
174
  "permissions": {"enabled": False}
135
175
  },
136
- "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
176
+ "registration": {
177
+ "enabled": False
178
+ },
179
+ "protocols": {
180
+ "enabled": True,
181
+ "allowed_protocols": ["https", "mtls"]
182
+ }
137
183
  }
138
- def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> Dict[str, Any]:
184
+
185
+
186
+ def generate_mtls_with_roles_config(
187
+ port: int = 20005,
188
+ certs_dir: str = "certs",
189
+ keys_dir: str = "keys",
190
+ roles_file: str = "configs/roles.json"
191
+ ) -> Dict[str, Any]:
139
192
  """Generate mTLS configuration with roles."""
140
193
  return {
141
194
  "server": {"host": "127.0.0.1", "port": port},
@@ -154,7 +207,11 @@ def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "certs",
154
207
  "proxy_info": {
155
208
  "name": "mcp_example_server",
156
209
  "capabilities": ["jsonrpc", "rest", "security", "proxy_registration"],
157
- "endpoints": {"jsonrpc": "/api/jsonrpc", "rest": "/cmd", "health": "/health"}
210
+ "endpoints": {
211
+ "jsonrpc": "/api/jsonrpc",
212
+ "rest": "/cmd",
213
+ "health": "/health"
214
+ }
158
215
  },
159
216
  "heartbeat": {"enabled": True, "interval": 30}
160
217
  },
@@ -163,8 +220,13 @@ def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "certs",
163
220
  "auth": {"enabled": True, "methods": ["certificate"]},
164
221
  "permissions": {"enabled": True, "roles_file": roles_file}
165
222
  },
166
- "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
223
+ "protocols": {
224
+ "enabled": True,
225
+ "allowed_protocols": ["https", "mtls"]
226
+ }
167
227
  }
228
+
229
+
168
230
  def generate_roles_config() -> Dict[str, Any]:
169
231
  """Generate roles configuration for testing."""
170
232
  return {
@@ -222,7 +284,14 @@ def generate_roles_config() -> Dict[str, Any]:
222
284
  "tokens": ["proxy-token-123"]
223
285
  }
224
286
  }
225
- def generate_all_configs(output_dir: str, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> None:
287
+
288
+
289
+ def generate_all_configs(
290
+ output_dir: str,
291
+ certs_dir: str = "certs",
292
+ keys_dir: str = "keys",
293
+ roles_file: str = "configs/roles.json"
294
+ ) -> None:
226
295
  """Generate all 6 configuration types and save them to files."""
227
296
  # Ensure output directory exists first
228
297
  os.makedirs(output_dir, exist_ok=True)
@@ -235,17 +304,17 @@ def generate_all_configs(output_dir: str, certs_dir: str = "certs", keys_dir: st
235
304
  "mtls_no_roles": generate_mtls_no_roles_config(20004, certs_dir, keys_dir),
236
305
  "mtls_with_roles": generate_mtls_with_roles_config(20005, certs_dir, keys_dir, roles_file)
237
306
  }
238
- # Ensure output directory exists
239
- os.makedirs(output_dir, exist_ok=True)
307
+
240
308
  # Generate each configuration
241
309
  for name, config in configs.items():
242
310
  filename = os.path.join(output_dir, f"{name}.json")
243
311
  with open(filename, 'w', encoding='utf-8') as f:
244
312
  json.dump(config, f, indent=2, ensure_ascii=False)
245
313
  print(f"Generated: {filename}")
314
+
246
315
  # Generate roles configuration
247
316
  roles_config = generate_roles_config()
248
-
317
+
249
318
  # Create roles.json in the root directory (test environment root) for compatibility
250
319
  # When running as module, we need to create roles.json in the current working directory
251
320
  # This is the directory where the user is running the command from
@@ -253,30 +322,30 @@ def generate_all_configs(output_dir: str, certs_dir: str = "certs", keys_dir: st
253
322
  # Get the current working directory where the user is running the command
254
323
  current_dir = os.getcwd()
255
324
  root_roles_filename = os.path.join(current_dir, "roles.json")
256
-
325
+
257
326
  # Create roles.json in the current working directory
258
327
  with open(root_roles_filename, 'w', encoding='utf-8') as f:
259
328
  json.dump(roles_config, f, indent=2, ensure_ascii=False)
260
329
  print(f"Generated: {root_roles_filename}")
261
-
330
+
262
331
  # Also create a copy in the output directory for reference
263
332
  backup_roles_filename = os.path.join(output_dir, "roles_backup.json")
264
333
  with open(backup_roles_filename, 'w', encoding='utf-8') as f:
265
334
  json.dump(roles_config, f, indent=2, ensure_ascii=False)
266
335
  print(f"Generated backup: {backup_roles_filename}")
267
-
336
+
268
337
  except Exception as e:
269
338
  print(f"Warning: Could not create roles.json in current directory: {e}")
270
339
  print(f"Current working directory: {os.getcwd()}")
271
340
  print(f"Script directory: {os.path.dirname(os.path.abspath(__file__))}")
272
-
341
+
273
342
  # Also create roles.json in configs directory for reference
274
343
  roles_filename = os.path.join(output_dir, "roles.json")
275
344
  with open(roles_filename, 'w', encoding='utf-8') as f:
276
345
  json.dump(roles_config, f, indent=2, ensure_ascii=False)
277
346
  print(f"Generated: {roles_filename}")
278
347
  print(f"\nGenerated {len(configs)} configuration files and roles.json in {output_dir}")
279
-
348
+
280
349
  print("\n" + "=" * 60)
281
350
  print("✅ CONFIGURATION GENERATION COMPLETED SUCCESSFULLY")
282
351
  print("=" * 60)
@@ -288,7 +357,9 @@ def generate_all_configs(output_dir: str, certs_dir: str = "certs", keys_dir: st
288
357
  print("\n3. Start full application example:")
289
358
  print(" python -m mcp_proxy_adapter.examples.full_application.main --config configs/mtls_with_roles.json")
290
359
  print("=" * 60)
291
- def main():
360
+
361
+
362
+ def main() -> int:
292
363
  """Main function for command line execution."""
293
364
  parser = argparse.ArgumentParser(
294
365
  description="Generate test configurations for MCP Proxy Adapter"
@@ -314,6 +385,7 @@ def main():
314
385
  help="Roles file path (default: configs/roles.json)"
315
386
  )
316
387
  args = parser.parse_args()
388
+
317
389
  try:
318
390
  generate_all_configs(args.output_dir, args.certs_dir, args.keys_dir, args.roles_file)
319
391
  print("Configuration generation completed successfully!")
@@ -327,5 +399,7 @@ def main():
327
399
  print("=" * 60)
328
400
  return 1
329
401
  return 0
402
+
403
+
330
404
  if __name__ == "__main__":
331
405
  exit(main())
@@ -262,7 +262,11 @@ class ConfigGenerator:
262
262
  - "https": HTTPS configuration
263
263
  - "https_token": HTTPS with token authentication
264
264
  - "mtls": mTLS configuration
265
-
265
+ - "optional_ssl": Configuration with optional SSL
266
+ - "optional_auth": Configuration with optional authentication
267
+ - "optional_proxy_reg": Configuration with optional proxy registration
268
+ - "custom": Custom configuration with specified features
269
+
266
270
  Returns:
267
271
  JSON configuration string with comments
268
272
  """
@@ -300,6 +304,14 @@ class ConfigGenerator:
300
304
  return self._get_mtls_config(base_config)
301
305
  elif config_type == "mtls_no_protocol_middleware":
302
306
  return self._get_mtls_no_protocol_middleware_config(base_config)
307
+ elif config_type == "optional_ssl":
308
+ return self._get_optional_ssl_config(base_config)
309
+ elif config_type == "optional_auth":
310
+ return self._get_optional_auth_config(base_config)
311
+ elif config_type == "optional_proxy_reg":
312
+ return self._get_optional_proxy_reg_config(base_config)
313
+ elif config_type == "custom":
314
+ return self._get_custom_config(base_config)
303
315
  else: # full
304
316
  return base_config
305
317
 
@@ -543,6 +555,245 @@ class ConfigGenerator:
543
555
 
544
556
  return config
545
557
 
558
+ def _get_optional_ssl_config(self, base_config: Dict[str, Any]) -> Dict[str, Any]:
559
+ """Get configuration with optional SSL support."""
560
+ config = base_config.copy()
561
+
562
+ # Server configuration
563
+ config["server"]["port"] = 8000
564
+
565
+ # SSL configuration - can be enabled/disabled via environment or config
566
+ config["ssl"]["enabled"] = False # Default disabled, can be enabled
567
+ config["ssl"]["cert_file"] = "mcp_proxy_adapter/examples/certs/server_cert.pem"
568
+ config["ssl"]["key_file"] = "mcp_proxy_adapter/examples/certs/server_key.pem"
569
+ config["ssl"]["ca_cert"] = "mcp_proxy_adapter/examples/certs/ca_cert.pem"
570
+ config["ssl"]["verify_client"] = False # Can be enabled for mTLS
571
+
572
+ # Security framework SSL - mirrors main SSL config
573
+ config["security"]["ssl"]["enabled"] = False # Default disabled
574
+ config["security"]["ssl"]["cert_file"] = "mcp_proxy_adapter/examples/certs/server_cert.pem"
575
+ config["security"]["ssl"]["key_file"] = "mcp_proxy_adapter/examples/certs/server_key.pem"
576
+ config["security"]["ssl"]["ca_cert_file"] = "mcp_proxy_adapter/examples/certs/ca_cert.pem"
577
+ config["security"]["ssl"]["client_cert_file"] = "mcp_proxy_adapter/examples/certs/client_cert.pem"
578
+ config["security"]["ssl"]["client_key_file"] = "mcp_proxy_adapter/examples/certs/client_key.key"
579
+
580
+ # Protocols support both HTTP and HTTPS
581
+ config["protocols"]["enabled"] = True
582
+ config["protocols"]["allowed_protocols"] = ["http", "https"]
583
+ config["protocols"]["default_protocol"] = "http"
584
+
585
+ # Enable proxy registration with token auth
586
+ config["registration"]["enabled"] = True
587
+ config["registration"]["auth_method"] = "token"
588
+ config["registration"]["token"]["enabled"] = True
589
+ config["registration"]["token"]["token"] = "proxy_registration_token_123"
590
+ config["registration"]["server_url"] = "http://127.0.0.1:3004/proxy"
591
+
592
+ return config
593
+
594
+ def _get_optional_auth_config(self, base_config: Dict[str, Any]) -> Dict[str, Any]:
595
+ """Get configuration with optional authentication support."""
596
+ config = base_config.copy()
597
+
598
+ # Server configuration
599
+ config["server"]["port"] = 8001
600
+
601
+ # SSL disabled by default
602
+ config["ssl"]["enabled"] = False
603
+ config["security"]["ssl"]["enabled"] = False
604
+
605
+ # Authentication configuration - can be enabled/disabled
606
+ config["security"]["auth"]["enabled"] = False # Default disabled
607
+ config["security"]["auth"]["methods"] = ["api_key", "jwt"] # Available methods
608
+
609
+ # API keys configuration
610
+ config["security"]["auth"]["api_keys"] = {
611
+ "admin-token": {
612
+ "roles": ["admin"],
613
+ "permissions": ["*"],
614
+ "expires": None
615
+ },
616
+ "user-token": {
617
+ "roles": ["user"],
618
+ "permissions": ["read", "execute"],
619
+ "expires": None
620
+ },
621
+ "guest-token": {
622
+ "roles": ["guest"],
623
+ "permissions": ["read"],
624
+ "expires": None
625
+ }
626
+ }
627
+
628
+ # JWT configuration
629
+ config["security"]["auth"]["jwt_secret"] = "your_jwt_secret_here"
630
+ config["security"]["auth"]["jwt_algorithm"] = "HS256"
631
+ config["security"]["auth"]["jwt_expiry_hours"] = 24
632
+
633
+ # User roles mapping
634
+ config["security"]["auth"]["user_roles"] = {
635
+ "admin": ["admin"],
636
+ "user": ["user"],
637
+ "guest": ["guest"]
638
+ }
639
+
640
+ # Permissions configuration - can be enabled/disabled
641
+ config["security"]["permissions"]["enabled"] = False # Default disabled
642
+ config["security"]["permissions"]["roles_file"] = "mcp_proxy_adapter/examples/server_configs/roles.json"
643
+ config["security"]["permissions"]["default_role"] = "guest"
644
+ config["security"]["permissions"]["admin_role"] = "admin"
645
+
646
+ # Protocols
647
+ config["protocols"]["enabled"] = True
648
+ config["protocols"]["allowed_protocols"] = ["http"]
649
+ config["protocols"]["default_protocol"] = "http"
650
+
651
+ # Enable proxy registration
652
+ config["registration"]["enabled"] = True
653
+ config["registration"]["auth_method"] = "token"
654
+ config["registration"]["token"]["enabled"] = True
655
+ config["registration"]["token"]["token"] = "proxy_registration_token_123"
656
+
657
+ return config
658
+
659
+ def _get_optional_proxy_reg_config(self, base_config: Dict[str, Any]) -> Dict[str, Any]:
660
+ """Get configuration with optional proxy registration support."""
661
+ config = base_config.copy()
662
+
663
+ # Server configuration
664
+ config["server"]["port"] = 8002
665
+
666
+ # SSL disabled by default
667
+ config["ssl"]["enabled"] = False
668
+ config["security"]["ssl"]["enabled"] = False
669
+
670
+ # Authentication disabled by default
671
+ config["security"]["auth"]["enabled"] = False
672
+ config["security"]["permissions"]["enabled"] = False
673
+
674
+ # Proxy registration configuration - can be enabled/disabled
675
+ config["registration"]["enabled"] = False # Default disabled
676
+ config["registration"]["server_url"] = "http://127.0.0.1:3004/proxy"
677
+ config["registration"]["server_id"] = "mcp_proxy_adapter"
678
+ config["registration"]["server_name"] = "MCP Proxy Adapter"
679
+ config["registration"]["description"] = "JSON-RPC API for interacting with MCP Proxy"
680
+
681
+ # Multiple authentication methods for proxy registration
682
+ config["registration"]["auth_method"] = "token" # Default method
683
+
684
+ # Token authentication
685
+ config["registration"]["token"]["enabled"] = True
686
+ config["registration"]["token"]["token"] = "proxy_registration_token_123"
687
+ config["registration"]["token"]["token_type"] = "bearer"
688
+ config["registration"]["token"]["refresh_interval"] = 3600
689
+
690
+ # Certificate authentication
691
+ config["registration"]["certificate"]["enabled"] = False
692
+ config["registration"]["certificate"]["cert_file"] = "mcp_proxy_adapter/examples/certs/proxy_client.crt"
693
+ config["registration"]["certificate"]["key_file"] = "mcp_proxy_adapter/examples/keys/proxy_client.key"
694
+ config["registration"]["certificate"]["ca_cert_file"] = "mcp_proxy_adapter/examples/certs/ca.crt"
695
+ config["registration"]["certificate"]["verify_server"] = True
696
+
697
+ # API key authentication
698
+ config["registration"]["api_key"]["enabled"] = False
699
+ config["registration"]["api_key"]["key"] = "proxy_api_key_456"
700
+ config["registration"]["api_key"]["key_header"] = "X-Proxy-API-Key"
701
+
702
+ # Proxy information
703
+ config["registration"]["proxy_info"]["name"] = "mcp_proxy_adapter"
704
+ config["registration"]["proxy_info"]["version"] = "1.0.0"
705
+ config["registration"]["proxy_info"]["description"] = "MCP Proxy Adapter with optional features"
706
+ config["registration"]["proxy_info"]["capabilities"] = ["jsonrpc", "rest", "optional_features"]
707
+ config["registration"]["proxy_info"]["endpoints"] = {
708
+ "jsonrpc": "/api/jsonrpc",
709
+ "rest": "/cmd",
710
+ "health": "/health"
711
+ }
712
+
713
+ # Heartbeat configuration
714
+ config["registration"]["heartbeat"]["enabled"] = True
715
+ config["registration"]["heartbeat"]["interval"] = 300
716
+ config["registration"]["heartbeat"]["timeout"] = 30
717
+ config["registration"]["heartbeat"]["retry_attempts"] = 3
718
+ config["registration"]["heartbeat"]["retry_delay"] = 60
719
+
720
+ # Auto-discovery
721
+ config["registration"]["auto_discovery"]["enabled"] = False
722
+ config["registration"]["auto_discovery"]["discovery_urls"] = []
723
+ config["registration"]["auto_discovery"]["discovery_interval"] = 3600
724
+ config["registration"]["auto_discovery"]["register_on_discovery"] = True
725
+
726
+ # Protocols
727
+ config["protocols"]["enabled"] = True
728
+ config["protocols"]["allowed_protocols"] = ["http"]
729
+ config["protocols"]["default_protocol"] = "http"
730
+
731
+ return config
732
+
733
+ def _get_custom_config(self, base_config: Dict[str, Any]) -> Dict[str, Any]:
734
+ """Get custom configuration with configurable features."""
735
+ config = base_config.copy()
736
+
737
+ # Server configuration
738
+ config["server"]["port"] = 8003
739
+
740
+ # SSL configuration - configurable
741
+ config["ssl"]["enabled"] = False # Can be enabled via config
742
+ config["ssl"]["cert_file"] = "mcp_proxy_adapter/examples/certs/server_cert.pem"
743
+ config["ssl"]["key_file"] = "mcp_proxy_adapter/examples/certs/server_key.pem"
744
+ config["ssl"]["ca_cert"] = "mcp_proxy_adapter/examples/certs/ca_cert.pem"
745
+ config["ssl"]["verify_client"] = False # Can be enabled for mTLS
746
+
747
+ # Security framework - configurable
748
+ config["security"]["enabled"] = False # Can be enabled via config
749
+ config["security"]["ssl"]["enabled"] = False # Mirrors main SSL
750
+ config["security"]["ssl"]["cert_file"] = "mcp_proxy_adapter/examples/certs/server_cert.pem"
751
+ config["security"]["ssl"]["key_file"] = "mcp_proxy_adapter/examples/certs/server_key.pem"
752
+ config["security"]["ssl"]["ca_cert_file"] = "mcp_proxy_adapter/examples/certs/ca_cert.pem"
753
+
754
+ # Authentication - configurable
755
+ config["security"]["auth"]["enabled"] = False # Can be enabled via config
756
+ config["security"]["auth"]["methods"] = ["api_key", "jwt", "certificate"]
757
+ config["security"]["auth"]["api_keys"] = {
758
+ "custom-admin": {
759
+ "roles": ["admin"],
760
+ "permissions": ["*"],
761
+ "expires": None
762
+ },
763
+ "custom-user": {
764
+ "roles": ["user"],
765
+ "permissions": ["read", "execute"],
766
+ "expires": None
767
+ }
768
+ }
769
+
770
+ # Permissions - configurable
771
+ config["security"]["permissions"]["enabled"] = False # Can be enabled via config
772
+ config["security"]["permissions"]["roles_file"] = "mcp_proxy_adapter/examples/server_configs/roles.json"
773
+
774
+ # Rate limiting - configurable
775
+ config["security"]["rate_limit"]["enabled"] = False # Can be enabled via config
776
+ config["security"]["rate_limit"]["default_requests_per_minute"] = 60
777
+ config["security"]["rate_limit"]["default_requests_per_hour"] = 1000
778
+
779
+ # Certificates - configurable
780
+ config["security"]["certificates"]["enabled"] = False # Can be enabled via config
781
+ config["security"]["certificates"]["cert_storage_path"] = "./certs"
782
+ config["security"]["certificates"]["key_storage_path"] = "./keys"
783
+
784
+ # Proxy registration - configurable
785
+ config["registration"]["enabled"] = False # Can be enabled via config
786
+ config["registration"]["auth_method"] = "token"
787
+ config["registration"]["token"]["enabled"] = True
788
+ config["registration"]["token"]["token"] = "custom_proxy_token"
789
+
790
+ # Protocols
791
+ config["protocols"]["enabled"] = True
792
+ config["protocols"]["allowed_protocols"] = ["http", "https"]
793
+ config["protocols"]["default_protocol"] = "http"
794
+
795
+ return config
796
+
546
797
  def _get_secure_config(self, base_config: Dict[str, Any]) -> Dict[str, Any]:
547
798
  """Get secure configuration with all security features enabled."""
548
799
  config = base_config.copy()
@@ -660,27 +911,42 @@ class ConfigGenerator:
660
911
  elif config_type == "mtls_no_protocol_middleware":
661
912
  base_comments["ssl"] = "SSL/TLS configuration (enabled for mTLS without ProtocolMiddleware)"
662
913
  base_comments["security"] = "Security framework configuration (mTLS mode without ProtocolMiddleware)"
914
+ elif config_type == "optional_ssl":
915
+ base_comments["ssl"] = "SSL/TLS configuration (optional, can be enabled/disabled)"
916
+ base_comments["security"] = "Security framework SSL configuration (mirrors main SSL)"
917
+ elif config_type == "optional_auth":
918
+ base_comments["ssl"] = "SSL/TLS configuration (disabled for optional auth)"
919
+ base_comments["security"] = "Security framework authentication configuration (optional, can be enabled/disabled)"
920
+ elif config_type == "optional_proxy_reg":
921
+ base_comments["ssl"] = "SSL/TLS configuration (disabled for optional proxy reg)"
922
+ base_comments["security"] = "Security framework proxy registration configuration (optional, can be enabled/disabled)"
923
+ elif config_type == "custom":
924
+ base_comments["ssl"] = "SSL/TLS configuration (configurable)"
925
+ base_comments["security"] = "Security framework configuration (configurable)"
926
+ base_comments["registration"] = "Proxy registration configuration (configurable)"
927
+ base_comments["protocols"] = "Protocol endpoints and settings (configurable)"
663
928
 
664
929
  return base_comments
665
930
 
666
931
  def generate_config_file(self, output_path: str, config_type: str = "full") -> None:
667
932
  """
668
933
  Generate configuration file and save to disk.
669
-
934
+
670
935
  Args:
671
936
  output_path: Path to save the configuration file
672
937
  config_type: Type of configuration to generate
673
938
  """
674
939
  try:
675
- config_content = self.generate_config_with_comments(config_type)
940
+ # Get configuration without comments for file generation
941
+ config = self._get_config_by_type(config_type)
676
942
 
677
943
  # Create directory if it doesn't exist
678
944
  output_file = Path(output_path)
679
945
  output_file.parent.mkdir(parents=True, exist_ok=True)
680
946
 
681
- # Write configuration file
947
+ # Write configuration file as clean JSON
682
948
  with open(output_file, 'w', encoding='utf-8') as f:
683
- f.write(config_content)
949
+ json.dump(config, f, indent=2, ensure_ascii=False)
684
950
 
685
951
  logger.info(f"Configuration file generated: {output_path}")
686
952
  logger.info(f"Configuration type: {config_type}")
@@ -699,7 +965,8 @@ class ConfigGenerator:
699
965
  config_types = [
700
966
  "minimal", "development", "secure", "full",
701
967
  "basic_http", "http_token", "https", "https_token", "mtls",
702
- "https_no_protocol_middleware", "mtls_no_protocol_middleware"
968
+ "https_no_protocol_middleware", "mtls_no_protocol_middleware",
969
+ "optional_ssl", "optional_auth", "optional_proxy_reg", "custom"
703
970
  ]
704
971
 
705
972
  for config_type in config_types:
@@ -717,7 +984,8 @@ def main():
717
984
  parser.add_argument("--type",
718
985
  choices=["minimal", "development", "secure", "full",
719
986
  "basic_http", "http_token", "https", "https_token", "mtls",
720
- "https_no_protocol_middleware", "mtls_no_protocol_middleware"],
987
+ "https_no_protocol_middleware", "mtls_no_protocol_middleware",
988
+ "optional_ssl", "optional_auth", "optional_proxy_reg", "custom"],
721
989
  default="full", help="Configuration type to generate")
722
990
  parser.add_argument("--output", default="./config.json",
723
991
  help="Output file path")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.2.25
3
+ Version: 6.2.27
4
4
  Summary: Powerful JSON-RPC microservices framework with built-in security, authentication, and proxy registration
5
5
  Home-page: https://github.com/maverikod/mcp-proxy-adapter
6
6
  Author: Vasiliy Zdanovskiy
@@ -1,6 +1,6 @@
1
1
  mcp_proxy_adapter/__init__.py,sha256=B7m1YWyv_Wb87-Q-JqVpHQgwajnfIgDyZ_iIxzdTbBY,1021
2
2
  mcp_proxy_adapter/__main__.py,sha256=-Wp1myP9DzJNB9j97mj62C8kFk5YUbCmd0e7Rnwte0A,769
3
- mcp_proxy_adapter/config.py,sha256=MgomeGL3XBO0tYOA6VIIP1hizUuTYpF9Bs2tp3cesMY,13333
3
+ mcp_proxy_adapter/config.py,sha256=ss6A-7Ef1I7iyZ-h-bzGWGwddB47642wEhN7uwnt5bk,21563
4
4
  mcp_proxy_adapter/custom_openapi.py,sha256=jYUrCy8C1mShh3sjKj-JkzSMLAvxDLTvtzSJFj5HUNg,15023
5
5
  mcp_proxy_adapter/main.py,sha256=9qt_pEQdq8roUc73CumfDn6jDWP_NyfdE1lCGEynv5I,2841
6
6
  mcp_proxy_adapter/openapi.py,sha256=36vOEbJjGnVZR6hUhl6mHCD29HYOEFKo2bL0JdGSm-4,13952
@@ -88,7 +88,7 @@ mcp_proxy_adapter/examples/demo_client.py,sha256=inic-FP5qG8oQXUaCrtEhmhac_PDZ1p
88
88
  mcp_proxy_adapter/examples/generate_all_certificates.py,sha256=rgcwqIkQ1eDfEIRFRXGIOz-jOSS1w0GPBRhYvMl6Vjc,16948
89
89
  mcp_proxy_adapter/examples/generate_certificates.py,sha256=A34OHUEiFvINOHrm3_JiDSbp-WG-eQXIvKCsE8JAeXQ,6616
90
90
  mcp_proxy_adapter/examples/generate_certificates_and_tokens.py,sha256=J0qHm_BMY8RYqfuwf7V7xKsHcsRJx8E7x-8JxmW5sPw,15988
91
- mcp_proxy_adapter/examples/generate_test_configs.py,sha256=NLhPrA9AfPlQ0WCbOJ1B_V9OC445tanKTmq7aAWKULU,13672
91
+ mcp_proxy_adapter/examples/generate_test_configs.py,sha256=OQjLJ0x1YrvYAFR1agu_Tl314KI_Mhjmo4o64H00wVw,14132
92
92
  mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=g59_QG2D1CCqhIXEvgy2XmgXI3toLmLyH7hL3uHZwC8,12647
93
93
  mcp_proxy_adapter/examples/run_example.py,sha256=o8rcy9Xo0UuZG4MpKdex3pFWYdtAi6uW8dEBQE6Yzbw,2539
94
94
  mcp_proxy_adapter/examples/run_full_test_suite.py,sha256=7Z6qDOvbndGPue1P9v-GcYZxy_XPqoC9voJ7tR8eKQ8,12428
@@ -131,10 +131,10 @@ mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py,sha25
131
131
  mcp_proxy_adapter/examples/scripts/config_generator.py,sha256=4qruYxQ2kGLVOukLX2JOW5kslJ06RhkNqTobAgh4rfw,32801
132
132
  mcp_proxy_adapter/examples/scripts/create_certificates_simple.py,sha256=xkIvUYl6hbKlWImQmenG0k_CvIsOsc9ZHICiKY3rtI8,26380
133
133
  mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py,sha256=J0qHm_BMY8RYqfuwf7V7xKsHcsRJx8E7x-8JxmW5sPw,15988
134
- mcp_proxy_adapter/utils/config_generator.py,sha256=4qruYxQ2kGLVOukLX2JOW5kslJ06RhkNqTobAgh4rfw,32801
135
- mcp_proxy_adapter-6.2.25.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
136
- mcp_proxy_adapter-6.2.25.dist-info/METADATA,sha256=cteiRynMPhEN2ErSDc0FtqAAZ_n0XgMwdLcvanfwnyQ,22348
137
- mcp_proxy_adapter-6.2.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
138
- mcp_proxy_adapter-6.2.25.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
139
- mcp_proxy_adapter-6.2.25.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
140
- mcp_proxy_adapter-6.2.25.dist-info/RECORD,,
134
+ mcp_proxy_adapter/utils/config_generator.py,sha256=2dxwBh9k_nUw9kgytZso5TNOQpBqd3c-RpKSTLoHlLE,46465
135
+ mcp_proxy_adapter-6.2.27.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
136
+ mcp_proxy_adapter-6.2.27.dist-info/METADATA,sha256=IrXoUBV-RR8hYdbUxWaeLPgacoo_c_8xoi0z_XJMzog,22348
137
+ mcp_proxy_adapter-6.2.27.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
138
+ mcp_proxy_adapter-6.2.27.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
139
+ mcp_proxy_adapter-6.2.27.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
140
+ mcp_proxy_adapter-6.2.27.dist-info/RECORD,,