mcp-proxy-adapter 6.4.48__py3-none-any.whl → 6.6.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.
@@ -0,0 +1,271 @@
1
+ """
2
+ Simplified configuration builder for MCP Proxy Adapter.
3
+
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+
8
+ import json
9
+ import uuid
10
+ from enum import Enum
11
+ from typing import Dict, List, Optional, Any
12
+
13
+
14
+ class Protocol(Enum):
15
+ """Supported protocols."""
16
+ HTTP = "http"
17
+ HTTPS = "https"
18
+ MTLS = "mtls"
19
+
20
+
21
+ class AuthMethod(Enum):
22
+ """Authentication methods."""
23
+ NONE = "none"
24
+ TOKEN = "token"
25
+ TOKEN_ROLES = "token_roles"
26
+
27
+
28
+ class ConfigBuilder:
29
+ """Simplified configuration builder."""
30
+
31
+ def __init__(self):
32
+ """Initialize the configuration builder."""
33
+ self._reset_to_defaults()
34
+
35
+ def _reset_to_defaults(self):
36
+ """Reset configuration to default values."""
37
+ self.config = {
38
+ "uuid": str(uuid.uuid4()),
39
+ "server": {
40
+ "host": "0.0.0.0",
41
+ "port": 8000,
42
+ "protocol": "http",
43
+ "debug": False,
44
+ "log_level": "INFO"
45
+ },
46
+ "logging": {
47
+ "level": "INFO",
48
+ "file": None,
49
+ "log_dir": "./logs",
50
+ "log_file": "mcp_proxy_adapter.log",
51
+ "max_size": 10,
52
+ "backup_count": 5,
53
+ "console_output": True,
54
+ "json_format": False
55
+ },
56
+ "security": {
57
+ "enabled": False,
58
+ "tokens": {
59
+ "admin": "admin-secret-key",
60
+ "user": "user-secret-key",
61
+ "readonly": "readonly-secret-key"
62
+ },
63
+ "roles": {
64
+ "admin": ["read", "write", "delete", "admin"],
65
+ "user": ["read", "write"],
66
+ "readonly": ["read"]
67
+ },
68
+ "roles_file": None
69
+ },
70
+ "debug": {
71
+ "enabled": False,
72
+ "log_level": "DEBUG",
73
+ "trace_requests": False,
74
+ "trace_responses": False
75
+ }
76
+ }
77
+
78
+ def set_protocol(self, protocol: Protocol, cert_dir: str = "./certs", key_dir: str = "./keys"):
79
+ """Set protocol configuration (HTTP, HTTPS, or mTLS)."""
80
+ self.config["server"]["protocol"] = protocol.value
81
+
82
+ if protocol == Protocol.HTTP:
83
+ # HTTP - no SSL
84
+ pass
85
+
86
+ elif protocol == Protocol.HTTPS:
87
+ # HTTPS - server SSL only
88
+ # SSL configuration will be handled by the server based on protocol
89
+ pass
90
+
91
+ elif protocol == Protocol.MTLS:
92
+ # mTLS - server SSL + client certificates
93
+ # SSL configuration will be handled by the server based on protocol
94
+ pass
95
+
96
+ return self
97
+
98
+ def set_auth(self, auth_method: AuthMethod, api_keys: Optional[Dict[str, str]] = None, roles: Optional[Dict[str, List[str]]] = None):
99
+ """Set authentication configuration."""
100
+ if auth_method == AuthMethod.NONE:
101
+ self.config["security"]["enabled"] = False
102
+ self.config["security"]["tokens"] = {}
103
+ self.config["security"]["roles"] = {}
104
+ self.config["security"]["roles_file"] = None
105
+
106
+ elif auth_method == AuthMethod.TOKEN:
107
+ self.config["security"]["enabled"] = True
108
+ self.config["security"]["tokens"] = api_keys or {
109
+ "admin": "admin-secret-key",
110
+ "user": "user-secret-key"
111
+ }
112
+ self.config["security"]["roles"] = {}
113
+ self.config["security"]["roles_file"] = None
114
+
115
+ elif auth_method == AuthMethod.TOKEN_ROLES:
116
+ self.config["security"]["enabled"] = True
117
+ self.config["security"]["tokens"] = api_keys or {
118
+ "admin": "admin-secret-key",
119
+ "user": "user-secret-key",
120
+ "readonly": "readonly-secret-key"
121
+ }
122
+ self.config["security"]["roles"] = roles or {
123
+ "admin": ["read", "write", "delete", "admin"],
124
+ "user": ["read", "write"],
125
+ "readonly": ["read"]
126
+ }
127
+ self.config["security"]["roles_file"] = "configs/roles.json"
128
+
129
+ return self
130
+
131
+ def set_server(self, host: str = "0.0.0.0", port: int = 8000):
132
+ """Set server configuration."""
133
+ self.config["server"]["host"] = host
134
+ self.config["server"]["port"] = port
135
+ return self
136
+
137
+ def set_roles_file(self, roles_file: str):
138
+ """Set roles file path."""
139
+ self.config["security"]["roles_file"] = roles_file
140
+ return self
141
+
142
+ def build(self) -> Dict[str, Any]:
143
+ """Build and return the configuration."""
144
+ return self.config.copy()
145
+
146
+ def save(self, file_path: str) -> None:
147
+ """Save configuration to file."""
148
+ with open(file_path, 'w', encoding='utf-8') as f:
149
+ json.dump(self.config, f, indent=2, ensure_ascii=False)
150
+
151
+
152
+ class ConfigFactory:
153
+ """Factory for creating common configurations."""
154
+
155
+ @staticmethod
156
+ def create_http_config(port: int = 8000) -> Dict[str, Any]:
157
+ """Create HTTP configuration."""
158
+ return (ConfigBuilder()
159
+ .set_protocol(Protocol.HTTP)
160
+ .set_server(port=port)
161
+ .build())
162
+
163
+ @staticmethod
164
+ def create_http_token_config(port: int = 8001) -> Dict[str, Any]:
165
+ """Create HTTP with token authentication configuration."""
166
+ return (ConfigBuilder()
167
+ .set_protocol(Protocol.HTTP)
168
+ .set_auth(AuthMethod.TOKEN)
169
+ .set_server(port=port)
170
+ .build())
171
+
172
+ @staticmethod
173
+ def create_http_token_roles_config(port: int = 8002) -> Dict[str, Any]:
174
+ """Create HTTP with token and roles configuration."""
175
+ return (ConfigBuilder()
176
+ .set_protocol(Protocol.HTTP)
177
+ .set_auth(AuthMethod.TOKEN_ROLES)
178
+ .set_server(port=port)
179
+ .build())
180
+
181
+ @staticmethod
182
+ def create_https_config(port: int = 8003) -> Dict[str, Any]:
183
+ """Create HTTPS configuration."""
184
+ return (ConfigBuilder()
185
+ .set_protocol(Protocol.HTTPS)
186
+ .set_server(port=port)
187
+ .build())
188
+
189
+ @staticmethod
190
+ def create_https_token_config(port: int = 8004) -> Dict[str, Any]:
191
+ """Create HTTPS with token authentication configuration."""
192
+ return (ConfigBuilder()
193
+ .set_protocol(Protocol.HTTPS)
194
+ .set_auth(AuthMethod.TOKEN)
195
+ .set_server(port=port)
196
+ .build())
197
+
198
+ @staticmethod
199
+ def create_https_token_roles_config(port: int = 8005) -> Dict[str, Any]:
200
+ """Create HTTPS with token and roles configuration."""
201
+ return (ConfigBuilder()
202
+ .set_protocol(Protocol.HTTPS)
203
+ .set_auth(AuthMethod.TOKEN_ROLES)
204
+ .set_server(port=port)
205
+ .build())
206
+
207
+ @staticmethod
208
+ def create_mtls_config(port: int = 8006) -> Dict[str, Any]:
209
+ """Create mTLS configuration."""
210
+ return (ConfigBuilder()
211
+ .set_protocol(Protocol.MTLS)
212
+ .set_server(port=port)
213
+ .build())
214
+
215
+ @staticmethod
216
+ def create_mtls_token_config(port: int = 8007) -> Dict[str, Any]:
217
+ """Create mTLS with token authentication configuration."""
218
+ return (ConfigBuilder()
219
+ .set_protocol(Protocol.MTLS)
220
+ .set_auth(AuthMethod.TOKEN)
221
+ .set_server(port=port)
222
+ .build())
223
+
224
+ @staticmethod
225
+ def create_mtls_token_roles_config(port: int = 8008) -> Dict[str, Any]:
226
+ """Create mTLS with token and roles configuration."""
227
+ return (ConfigBuilder()
228
+ .set_protocol(Protocol.MTLS)
229
+ .set_auth(AuthMethod.TOKEN_ROLES)
230
+ .set_server(port=port)
231
+ .build())
232
+
233
+
234
+ def create_config_from_flags(protocol: str, token: bool = False, roles: bool = False, port: int = 8000) -> Dict[str, Any]:
235
+ """
236
+ Create configuration from command line flags.
237
+
238
+ Args:
239
+ protocol: Protocol type (http, https, mtls)
240
+ token: Enable token authentication
241
+ roles: Enable role-based access control
242
+ port: Server port
243
+
244
+ Returns:
245
+ Configuration dictionary
246
+ """
247
+ protocol_map = {
248
+ "http": Protocol.HTTP,
249
+ "https": Protocol.HTTPS,
250
+ "mtls": Protocol.MTLS
251
+ }
252
+
253
+ if protocol not in protocol_map:
254
+ raise ValueError(f"Unsupported protocol: {protocol}")
255
+
256
+ builder = ConfigBuilder().set_protocol(protocol_map[protocol]).set_server(port=port)
257
+
258
+ if roles:
259
+ builder.set_auth(AuthMethod.TOKEN_ROLES)
260
+ elif token:
261
+ builder.set_auth(AuthMethod.TOKEN)
262
+ else:
263
+ builder.set_auth(AuthMethod.NONE)
264
+
265
+ return builder.build()
266
+
267
+
268
+ if __name__ == "__main__":
269
+ # Example usage
270
+ config = create_config_from_flags("http", token=True, port=8001)
271
+ print(json.dumps(config, indent=2))
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Configuration Generator CLI for MCP Proxy Adapter
4
+ Generates configurations based on command line flags.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+ import argparse
10
+ import json
11
+ import sys
12
+ from pathlib import Path
13
+ from typing import Dict, Any, Optional
14
+
15
+ # Add the examples directory to the path to import config_builder
16
+ sys.path.insert(0, str(Path(__file__).parent / "mcp_proxy_adapter" / "examples"))
17
+
18
+ from config_builder import ConfigBuilder, ConfigFactory, Protocol, AuthMethod
19
+
20
+
21
+ def create_config_from_flags(
22
+ protocol: str,
23
+ token: bool = False,
24
+ roles: bool = False,
25
+ host: str = "127.0.0.1",
26
+ port: int = 8000,
27
+ cert_dir: str = "./certs",
28
+ key_dir: str = "./keys",
29
+ output_dir: str = "./configs"
30
+ ) -> Dict[str, Any]:
31
+ """
32
+ Create configuration based on command line flags.
33
+
34
+ Args:
35
+ protocol: Protocol type (http, https, mtls)
36
+ token: Enable token authentication
37
+ roles: Enable role-based access control
38
+ host: Server host
39
+ port: Server port
40
+ cert_dir: Certificate directory
41
+ key_dir: Key directory
42
+ output_dir: Output directory for configs
43
+
44
+ Returns:
45
+ Configuration dictionary
46
+ """
47
+ # Use the simplified config builder
48
+ from config_builder import create_config_from_flags as simple_create_config
49
+
50
+ return simple_create_config(protocol, token, roles, port)
51
+
52
+
53
+ def save_config(config: Dict[str, Any], filename: str, output_dir: str) -> Path:
54
+ """Save configuration to file."""
55
+ output_path = Path(output_dir)
56
+ output_path.mkdir(parents=True, exist_ok=True)
57
+
58
+ config_file = output_path / f"{filename}.json"
59
+ with open(config_file, 'w', encoding='utf-8') as f:
60
+ json.dump(config, f, indent=2, ensure_ascii=False)
61
+
62
+ return config_file
63
+
64
+
65
+ def create_full_config_with_all_options(host: str = "127.0.0.1", port: int = 20000) -> Dict[str, Any]:
66
+ """
67
+ Create a full configuration with all options enabled but set to HTTP base.
68
+ This allows testing all features by enabling different sections.
69
+
70
+ Args:
71
+ host: Server host
72
+ port: Server port
73
+
74
+ Returns:
75
+ Full configuration dictionary with all options
76
+ """
77
+ builder = ConfigBuilder()
78
+
79
+ # Set server configuration
80
+ builder.set_server(host=host, port=port)
81
+
82
+ # Set to HTTP base (no SSL by default)
83
+ builder.set_protocol(Protocol.HTTP)
84
+
85
+ # Enable all authentication options but keep them disabled by default
86
+ api_keys = {
87
+ "admin": "admin-secret-key",
88
+ "user": "user-secret-key",
89
+ "readonly": "readonly-secret-key"
90
+ }
91
+ roles = {
92
+ "admin": ["read", "write", "delete", "admin"],
93
+ "user": ["read", "write"],
94
+ "readonly": ["read"]
95
+ }
96
+
97
+ # Set up all authentication methods but keep security disabled
98
+ builder.set_auth(AuthMethod.TOKEN_ROLES, api_keys=api_keys, roles=roles)
99
+
100
+ # Disable security by default (will be enabled in tests)
101
+ config = builder.build()
102
+ config["security"]["enabled"] = False
103
+
104
+ # Add protocol variants for easy switching
105
+ config["protocol_variants"] = {
106
+ "http": {"server": {"protocol": "http"}},
107
+ "https": {"server": {"protocol": "https"}},
108
+ "mtls": {"server": {"protocol": "mtls"}}
109
+ }
110
+
111
+ # Add authentication configurations for easy switching
112
+ config["auth_variants"] = {
113
+ "none": {"security": {"enabled": False}},
114
+ "token": {
115
+ "security": {
116
+ "enabled": True,
117
+ "tokens": api_keys,
118
+ "roles": roles,
119
+ "roles_file": None
120
+ }
121
+ },
122
+ "token_roles": {
123
+ "security": {
124
+ "enabled": True,
125
+ "tokens": api_keys,
126
+ "roles": roles,
127
+ "roles_file": "configs/roles.json"
128
+ }
129
+ }
130
+ }
131
+
132
+ return config
133
+
134
+
135
+ def generate_all_configs(output_dir: str = "./configs", host: str = "127.0.0.1") -> None:
136
+ """Generate all standard configurations."""
137
+ configs = [
138
+ # HTTP configurations
139
+ ("http", False, False, 20000),
140
+ ("http", True, True, 20001), # token=True always includes roles
141
+ ("http", True, True, 20002), # token_roles is same as token now
142
+
143
+ # HTTPS configurations
144
+ ("https", False, False, 20003),
145
+ ("https", True, True, 20004), # token=True always includes roles
146
+ ("https", True, True, 20005), # token_roles is same as token now
147
+
148
+ # mTLS configurations
149
+ ("mtls", False, False, 20006),
150
+ ("mtls", True, True, 20007), # token=True always includes roles
151
+ ("mtls", True, True, 20008), # token_roles is same as token now
152
+ ]
153
+
154
+ print("🔧 Generating MCP Proxy Adapter configurations...")
155
+ print("=" * 60)
156
+
157
+ generated_files = []
158
+
159
+ for protocol, token, roles, port in configs:
160
+ # Create configuration name
161
+ name_parts = [protocol]
162
+ if token:
163
+ name_parts.append("token")
164
+ if roles:
165
+ name_parts.append("roles")
166
+
167
+ config_name = "_".join(name_parts)
168
+
169
+ # Generate configuration
170
+ config = create_config_from_flags(
171
+ protocol=protocol,
172
+ token=token,
173
+ roles=roles,
174
+ host=host,
175
+ port=port,
176
+ output_dir=output_dir
177
+ )
178
+
179
+ # Save configuration
180
+ config_file = save_config(config, config_name, output_dir)
181
+ generated_files.append(config_file)
182
+
183
+ print(f"✅ Created {config_name}.json (port {port})")
184
+
185
+ # Create roles.json file if any role-based configs were generated
186
+ roles_config = {
187
+ "enabled": True,
188
+ "default_policy": {
189
+ "deny_by_default": False,
190
+ "require_role_match": False,
191
+ "case_sensitive": False,
192
+ "allow_wildcard": False
193
+ },
194
+ "roles": {
195
+ "admin": ["read", "write", "delete", "admin"],
196
+ "user": ["read", "write"],
197
+ "readonly": ["read"],
198
+ "guest": ["read"],
199
+ "proxy": ["read", "write"]
200
+ },
201
+ "permissions": {
202
+ "read": ["GET"],
203
+ "write": ["POST", "PUT", "PATCH"],
204
+ "delete": ["DELETE"],
205
+ "admin": ["*"]
206
+ }
207
+ }
208
+
209
+ roles_file = Path(output_dir) / "roles.json"
210
+ with open(roles_file, 'w', encoding='utf-8') as f:
211
+ json.dump(roles_config, f, indent=2, ensure_ascii=False)
212
+ print(f"✅ Created roles.json")
213
+
214
+ print(f"\n🎉 Generated {len(generated_files)} configurations in {output_dir}/")
215
+ print("\n📋 Generated configurations:")
216
+ for config_file in generated_files:
217
+ print(f" - {config_file.name}")
218
+
219
+
220
+ def main():
221
+ """Main CLI function."""
222
+ parser = argparse.ArgumentParser(
223
+ description="MCP Proxy Adapter Configuration Generator",
224
+ formatter_class=argparse.RawDescriptionHelpFormatter,
225
+ epilog="""
226
+ Examples:
227
+ # Generate all standard configurations
228
+ python generate_config.py --all
229
+
230
+ # Generate full config with all options (HTTP base)
231
+ python generate_config.py --full-config
232
+
233
+ # Generate specific configuration
234
+ python generate_config.py --protocol https --token --roles --port 8080
235
+
236
+ # Generate HTTP configuration with token auth
237
+ python generate_config.py --protocol http --token
238
+
239
+ # Generate mTLS configuration with roles
240
+ python generate_config.py --protocol mtls --roles
241
+ """
242
+ )
243
+
244
+ # Configuration options
245
+ parser.add_argument("--protocol", choices=["http", "https", "mtls"],
246
+ help="Protocol type (http, https, mtls)")
247
+ parser.add_argument("--token", action="store_true",
248
+ help="Enable token authentication")
249
+ parser.add_argument("--roles", action="store_true",
250
+ help="Enable role-based access control")
251
+ parser.add_argument("--all", action="store_true",
252
+ help="Generate all standard configurations")
253
+ parser.add_argument("--full-config", action="store_true",
254
+ help="Generate full config with all options (HTTP base)")
255
+
256
+ # Server configuration
257
+ parser.add_argument("--host", default="127.0.0.1",
258
+ help="Server host (default: 127.0.0.1)")
259
+ parser.add_argument("--port", type=int, default=8000,
260
+ help="Server port (default: 8000)")
261
+
262
+ # Paths
263
+ parser.add_argument("--cert-dir", default="./certs",
264
+ help="Certificate directory (default: ./certs)")
265
+ parser.add_argument("--key-dir", default="./keys",
266
+ help="Key directory (default: ./keys)")
267
+ parser.add_argument("--output-dir", default="./configs",
268
+ help="Output directory (default: ./configs)")
269
+
270
+ # Output options
271
+ parser.add_argument("--output", "-o",
272
+ help="Output filename (without extension)")
273
+ parser.add_argument("--stdout", action="store_true",
274
+ help="Output to stdout instead of file")
275
+
276
+ args = parser.parse_args()
277
+
278
+ try:
279
+ if args.all:
280
+ # Generate all configurations
281
+ generate_all_configs(
282
+ output_dir=args.output_dir,
283
+ host=args.host
284
+ )
285
+ elif args.full_config:
286
+ # Generate full config with all options
287
+ config = create_full_config_with_all_options(
288
+ host=args.host,
289
+ port=args.port
290
+ )
291
+
292
+ if args.stdout:
293
+ # Output to stdout
294
+ print(json.dumps(config, indent=2, ensure_ascii=False))
295
+ else:
296
+ # Save to file
297
+ filename = args.output or "full_config"
298
+ config_file = save_config(config, filename, args.output_dir)
299
+ print(f"✅ Full configuration saved to: {config_file}")
300
+ elif args.protocol:
301
+ # Generate specific configuration
302
+ config = create_config_from_flags(
303
+ protocol=args.protocol,
304
+ token=args.token,
305
+ roles=args.roles,
306
+ host=args.host,
307
+ port=args.port,
308
+ cert_dir=args.cert_dir,
309
+ key_dir=args.key_dir,
310
+ output_dir=args.output_dir
311
+ )
312
+
313
+ if args.stdout:
314
+ # Output to stdout
315
+ print(json.dumps(config, indent=2, ensure_ascii=False))
316
+ else:
317
+ # Save to file
318
+ if args.output:
319
+ filename = args.output
320
+ else:
321
+ # Generate filename from flags
322
+ name_parts = [args.protocol]
323
+ if args.token:
324
+ name_parts.append("token")
325
+ if args.roles:
326
+ name_parts.append("roles")
327
+ filename = "_".join(name_parts)
328
+
329
+ config_file = save_config(config, filename, args.output_dir)
330
+ print(f"✅ Configuration saved to: {config_file}")
331
+ else:
332
+ parser.print_help()
333
+ return 1
334
+
335
+ return 0
336
+
337
+ except Exception as e:
338
+ print(f"❌ Error: {e}", file=sys.stderr)
339
+ return 1
340
+
341
+
342
+ if __name__ == "__main__":
343
+ sys.exit(main())