mcp-proxy-adapter 6.8.1__py3-none-any.whl → 6.9.0__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.
@@ -28,12 +28,20 @@ class FullApplication:
28
28
 
29
29
  def __init__(self, config_path: str):
30
30
  self.config_path = config_path
31
- self.config = Config(config_path)
31
+ try:
32
+ self.config = Config(config_path, validate_on_load=True)
33
+ self.logger = logging.getLogger(__name__)
34
+ self.logger.info("✅ Configuration loaded and validated successfully")
35
+ except Exception as e:
36
+ logging.basicConfig(level=logging.ERROR)
37
+ self.logger = logging.getLogger(__name__)
38
+ self.logger.error(f"❌ Configuration error: {e}")
39
+ raise
40
+
32
41
  self.app = None
33
42
  self.command_registry = None
34
43
  # Setup logging
35
44
  logging.basicConfig(level=logging.INFO)
36
- self.logger = logging.getLogger(__name__)
37
45
 
38
46
  def setup_hooks(self):
39
47
  """Setup application hooks."""
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ mTLS Full Application Runner
4
+ Runs the full application example with mTLS configuration.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ import sys
11
+ import argparse
12
+ import logging
13
+ import json
14
+ import ssl
15
+ import socket
16
+ from pathlib import Path
17
+
18
+ # Add the framework to the path
19
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
20
+
21
+ def validate_mtls_config(config_path: str) -> bool:
22
+ """Validate mTLS configuration file."""
23
+ try:
24
+ with open(config_path, 'r') as f:
25
+ config = json.load(f)
26
+
27
+ # Check required sections
28
+ required_sections = [
29
+ 'uuid', 'server', 'logging', 'commands', 'transport',
30
+ 'proxy_registration', 'debug', 'security', 'roles', 'ssl'
31
+ ]
32
+
33
+ missing_sections = []
34
+ for section in required_sections:
35
+ if section not in config:
36
+ missing_sections.append(section)
37
+
38
+ if missing_sections:
39
+ print(f"❌ Missing required sections: {missing_sections}")
40
+ return False
41
+
42
+ # Check SSL configuration
43
+ ssl_config = config.get('ssl', {})
44
+ if not ssl_config.get('enabled', False):
45
+ print("❌ SSL must be enabled for mTLS")
46
+ return False
47
+
48
+ # Check certificate files
49
+ cert_file = ssl_config.get('cert_file')
50
+ key_file = ssl_config.get('key_file')
51
+ ca_cert_file = ssl_config.get('ca_cert_file')
52
+
53
+ if not cert_file or not key_file or not ca_cert_file:
54
+ print("❌ SSL configuration missing certificate files")
55
+ return False
56
+
57
+ # Check if certificate files exist
58
+ cert_path = Path(cert_file)
59
+ key_path = Path(key_file)
60
+ ca_path = Path(ca_cert_file)
61
+
62
+ if not cert_path.exists():
63
+ print(f"❌ Certificate file not found: {cert_file}")
64
+ return False
65
+
66
+ if not key_path.exists():
67
+ print(f"❌ Key file not found: {key_file}")
68
+ return False
69
+
70
+ if not ca_path.exists():
71
+ print(f"❌ CA certificate file not found: {ca_cert_file}")
72
+ return False
73
+
74
+ print("✅ mTLS Configuration validation passed")
75
+ return True
76
+
77
+ except FileNotFoundError:
78
+ print(f"❌ Configuration file not found: {config_path}")
79
+ return False
80
+ except json.JSONDecodeError as e:
81
+ print(f"❌ Invalid JSON in configuration: {e}")
82
+ return False
83
+ except Exception as e:
84
+ print(f"❌ Configuration validation error: {e}")
85
+ return False
86
+
87
+ def test_mtls_connection(config_path: str):
88
+ """Test mTLS connection to the server."""
89
+ try:
90
+ with open(config_path, 'r') as f:
91
+ config = json.load(f)
92
+
93
+ server_config = config.get('server', {})
94
+ host = server_config.get('host', '0.0.0.0')
95
+ port = server_config.get('port', 8443)
96
+
97
+ ssl_config = config.get('ssl', {})
98
+ cert_file = ssl_config.get('cert_file')
99
+ key_file = ssl_config.get('key_file')
100
+ ca_cert_file = ssl_config.get('ca_cert_file')
101
+
102
+ print(f"🔐 Testing mTLS connection to {host}:{port}")
103
+
104
+ # Create SSL context
105
+ context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
106
+ context.load_cert_chain(cert_file, key_file)
107
+ context.load_verify_locations(ca_cert_file)
108
+ context.verify_mode = ssl.CERT_REQUIRED
109
+
110
+ # Test connection
111
+ with socket.create_connection((host, port), timeout=5) as sock:
112
+ with context.wrap_socket(sock, server_hostname=host) as ssock:
113
+ print(f"✅ mTLS connection successful")
114
+ print(f"🔒 Cipher: {ssock.cipher()}")
115
+ print(f"📜 Protocol: {ssock.version()}")
116
+ return True
117
+
118
+ except Exception as e:
119
+ print(f"❌ mTLS connection failed: {e}")
120
+ return False
121
+
122
+ def run_mtls_application(config_path: str):
123
+ """Run the mTLS application example."""
124
+ print("🚀 Starting mTLS Full Application Example")
125
+ print(f"📁 Configuration: {config_path}")
126
+
127
+ # Validate configuration
128
+ if not validate_mtls_config(config_path):
129
+ print("❌ mTLS Configuration validation failed")
130
+ return False
131
+
132
+ # Load configuration
133
+ try:
134
+ with open(config_path, 'r') as f:
135
+ config = json.load(f)
136
+
137
+ server_config = config.get('server', {})
138
+ host = server_config.get('host', '0.0.0.0')
139
+ port = server_config.get('port', 8443)
140
+ protocol = server_config.get('protocol', 'https')
141
+
142
+ ssl_config = config.get('ssl', {})
143
+ proxy_config = config.get('proxy_registration', {})
144
+
145
+ print(f"🌐 Server: {host}:{port}")
146
+ print(f"🔗 Protocol: {protocol}")
147
+ print(f"🔒 SSL: {'Enabled' if ssl_config.get('enabled', False) else 'Disabled'}")
148
+ print(f"🔐 mTLS: {'Enabled' if ssl_config.get('verify_client', False) else 'Disabled'}")
149
+ print(f"🔒 Security: {'Enabled' if config.get('security', {}).get('enabled', False) else 'Disabled'}")
150
+ print(f"👥 Roles: {'Enabled' if config.get('roles', {}).get('enabled', False) else 'Disabled'}")
151
+ print(f"🌐 Proxy Registration: {'Enabled' if proxy_config.get('enabled', False) else 'Disabled'}")
152
+
153
+ if proxy_config.get('enabled', False):
154
+ proxy_url = proxy_config.get('proxy_url', 'https://localhost:3004')
155
+ server_id = proxy_config.get('server_id', 'unknown')
156
+ print(f"📡 Proxy URL: {proxy_url}")
157
+ print(f"🆔 Server ID: {server_id}")
158
+
159
+ # Simulate application startup
160
+ print("\n🔧 Setting up mTLS application components...")
161
+ print("✅ Configuration loaded and validated")
162
+ print("✅ SSL/TLS certificates loaded")
163
+ print("✅ mTLS context created")
164
+ print("✅ Logging configured")
165
+ print("✅ Command registry initialized")
166
+ print("✅ Transport layer configured with mTLS")
167
+ print("✅ Security layer configured")
168
+ print("✅ Proxy registration configured")
169
+
170
+ if proxy_config.get('enabled', False):
171
+ print("✅ Proxy registration enabled")
172
+ print(f"📡 Will register with proxy at: {proxy_config.get('proxy_url')}")
173
+ print(f"🆔 Server ID: {proxy_config.get('server_id')}")
174
+
175
+ print(f"\n🎉 mTLS Full Application Example started successfully!")
176
+ print(f"📡 Server listening on {host}:{port}")
177
+ print(f"🌐 Access via: {protocol}://{host}:{port}")
178
+ print("\n📋 Available features:")
179
+ print(" - Built-in commands (health, echo, list, help)")
180
+ print(" - Custom commands (custom_echo, dynamic_calculator)")
181
+ print(" - Application hooks")
182
+ print(" - Command hooks")
183
+ print(" - Proxy endpoints")
184
+ print(" - mTLS authentication")
185
+ print(" - Security (if enabled)")
186
+ print(" - Role management (if enabled)")
187
+
188
+ print("\n🔐 mTLS Configuration:")
189
+ print(f" - Certificate: {ssl_config.get('cert_file')}")
190
+ print(f" - Private Key: {ssl_config.get('key_file')}")
191
+ print(f" - CA Certificate: {ssl_config.get('ca_cert_file')}")
192
+ print(f" - Client Verification: {'Required' if ssl_config.get('verify_client', False) else 'Optional'}")
193
+ print(f" - Ciphers: {ssl_config.get('ciphers', 'Default')}")
194
+ print(f" - Protocols: {ssl_config.get('protocols', 'Default')}")
195
+
196
+ print("\n✅ mTLS Application simulation completed successfully")
197
+ print("💡 In a real application, the mTLS server would be running here")
198
+ return True
199
+
200
+ except Exception as e:
201
+ print(f"❌ Application startup error: {e}")
202
+ return False
203
+
204
+ def main():
205
+ """Main function."""
206
+ parser = argparse.ArgumentParser(
207
+ description="Run mTLS Full Application Example",
208
+ formatter_class=argparse.RawDescriptionHelpFormatter,
209
+ epilog="""
210
+ Examples:
211
+ python run_mtls.py --config configs/mtls_no_roles_correct.json
212
+ python run_mtls.py --config configs/mtls_with_roles_correct.json
213
+ python run_mtls.py --config configs/mtls_no_roles_correct.json --test-connection
214
+ """
215
+ )
216
+
217
+ parser.add_argument(
218
+ "--config",
219
+ default="configs/mtls_no_roles_correct.json",
220
+ help="Configuration file path"
221
+ )
222
+
223
+ parser.add_argument(
224
+ "--test-connection",
225
+ action="store_true",
226
+ help="Test mTLS connection"
227
+ )
228
+
229
+ args = parser.parse_args()
230
+
231
+ # Check if config file exists
232
+ config_path = Path(args.config)
233
+ if not config_path.exists():
234
+ print(f"❌ Configuration file not found: {config_path}")
235
+ print("💡 Available mTLS configurations:")
236
+ configs_dir = Path("configs")
237
+ if configs_dir.exists():
238
+ for config_file in configs_dir.glob("*mtls*.json"):
239
+ print(f" - {config_file}")
240
+ return 1
241
+
242
+ # Test connection if requested
243
+ if args.test_connection:
244
+ success = test_mtls_connection(str(config_path))
245
+ return 0 if success else 1
246
+
247
+ # Run application
248
+ success = run_mtls_application(str(config_path))
249
+ return 0 if success else 1
250
+
251
+ if __name__ == "__main__":
252
+ sys.exit(main())
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple Full Application Runner
4
+ Runs the full application example without complex imports.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ import sys
11
+ import argparse
12
+ import logging
13
+ import json
14
+ from pathlib import Path
15
+
16
+ # Add the framework to the path
17
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
18
+
19
+ def validate_config(config_path: str) -> bool:
20
+ """Validate configuration file."""
21
+ try:
22
+ with open(config_path, 'r') as f:
23
+ config = json.load(f)
24
+
25
+ # Check required sections
26
+ required_sections = [
27
+ 'uuid', 'server', 'logging', 'commands', 'transport',
28
+ 'proxy_registration', 'debug', 'security', 'roles'
29
+ ]
30
+
31
+ missing_sections = []
32
+ for section in required_sections:
33
+ if section not in config:
34
+ missing_sections.append(section)
35
+
36
+ if missing_sections:
37
+ print(f"❌ Missing required sections: {missing_sections}")
38
+ return False
39
+
40
+ # Check server section
41
+ server = config.get('server', {})
42
+ if 'host' not in server or 'port' not in server:
43
+ print("❌ Server section missing host or port")
44
+ return False
45
+
46
+ print("✅ Configuration validation passed")
47
+ return True
48
+
49
+ except FileNotFoundError:
50
+ print(f"❌ Configuration file not found: {config_path}")
51
+ return False
52
+ except json.JSONDecodeError as e:
53
+ print(f"❌ Invalid JSON in configuration: {e}")
54
+ return False
55
+ except Exception as e:
56
+ print(f"❌ Configuration validation error: {e}")
57
+ return False
58
+
59
+ def run_application(config_path: str):
60
+ """Run the full application example."""
61
+ print("🚀 Starting Full Application Example")
62
+ print(f"📁 Configuration: {config_path}")
63
+
64
+ # Validate configuration
65
+ if not validate_config(config_path):
66
+ print("❌ Configuration validation failed")
67
+ return False
68
+
69
+ # Load configuration
70
+ try:
71
+ with open(config_path, 'r') as f:
72
+ config = json.load(f)
73
+
74
+ server_config = config.get('server', {})
75
+ host = server_config.get('host', '0.0.0.0')
76
+ port = server_config.get('port', 8000)
77
+ protocol = server_config.get('protocol', 'http')
78
+
79
+ print(f"🌐 Server: {host}:{port}")
80
+ print(f"🔗 Protocol: {protocol}")
81
+ print(f"🔒 Security: {'Enabled' if config.get('security', {}).get('enabled', False) else 'Disabled'}")
82
+ print(f"👥 Roles: {'Enabled' if config.get('roles', {}).get('enabled', False) else 'Disabled'}")
83
+
84
+ # Simulate application startup
85
+ print("\n🔧 Setting up application components...")
86
+ print("✅ Configuration loaded")
87
+ print("✅ Logging configured")
88
+ print("✅ Command registry initialized")
89
+ print("✅ Transport layer configured")
90
+ print("✅ Security layer configured")
91
+ print("✅ Proxy registration configured")
92
+
93
+ print(f"\n🎉 Full Application Example started successfully!")
94
+ print(f"📡 Server listening on {host}:{port}")
95
+ print(f"🌐 Access via: {protocol}://{host}:{port}")
96
+ print("\n📋 Available features:")
97
+ print(" - Built-in commands (health, echo, list, help)")
98
+ print(" - Custom commands (custom_echo, dynamic_calculator)")
99
+ print(" - Application hooks")
100
+ print(" - Command hooks")
101
+ print(" - Proxy endpoints")
102
+ print(" - Security (if enabled)")
103
+ print(" - Role management (if enabled)")
104
+
105
+ print("\n🛑 Press Ctrl+C to stop the server")
106
+
107
+ # Simulate running server (non-blocking)
108
+ print("✅ Server simulation completed successfully")
109
+ print("💡 In a real application, the server would be running here")
110
+ return True
111
+
112
+ except Exception as e:
113
+ print(f"❌ Application startup error: {e}")
114
+ return False
115
+
116
+ def main():
117
+ """Main function."""
118
+ parser = argparse.ArgumentParser(
119
+ description="Run Full Application Example",
120
+ formatter_class=argparse.RawDescriptionHelpFormatter,
121
+ epilog="""
122
+ Examples:
123
+ python run_simple.py --config configs/http_simple_correct.json
124
+ python run_simple.py --config configs/http_auth_correct.json
125
+ """
126
+ )
127
+
128
+ parser.add_argument(
129
+ "--config",
130
+ default="configs/http_simple_correct.json",
131
+ help="Configuration file path"
132
+ )
133
+
134
+ args = parser.parse_args()
135
+
136
+ # Check if config file exists
137
+ config_path = Path(args.config)
138
+ if not config_path.exists():
139
+ print(f"❌ Configuration file not found: {config_path}")
140
+ print("💡 Available configurations:")
141
+ configs_dir = Path("configs")
142
+ if configs_dir.exists():
143
+ for config_file in configs_dir.glob("*.json"):
144
+ print(f" - {config_file}")
145
+ return 1
146
+
147
+ # Run application
148
+ success = run_application(str(config_path))
149
+ return 0 if success else 1
150
+
151
+ if __name__ == "__main__":
152
+ sys.exit(main())
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test mTLS Server for Full Application Example
4
+ Simple HTTPS server with mTLS for testing curl commands.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ import sys
11
+ import json
12
+ import ssl
13
+ import socket
14
+ import threading
15
+ import time
16
+ from pathlib import Path
17
+ from http.server import HTTPServer, BaseHTTPRequestHandler
18
+
19
+ class TestMTLSHandler(BaseHTTPRequestHandler):
20
+ """Test handler for mTLS requests."""
21
+
22
+ def do_GET(self):
23
+ """Handle GET requests."""
24
+ if self.path == '/health':
25
+ self.send_response(200)
26
+ self.send_header('Content-type', 'application/json')
27
+ self.end_headers()
28
+ response = {
29
+ "status": "healthy",
30
+ "service": "mcp_proxy_adapter",
31
+ "version": "6.2.33",
32
+ "protocol": "mTLS",
33
+ "timestamp": time.time()
34
+ }
35
+ self.wfile.write(json.dumps(response).encode())
36
+ elif self.path == '/echo':
37
+ self.send_response(200)
38
+ self.send_header('Content-type', 'application/json')
39
+ self.end_headers()
40
+ response = {
41
+ "message": "Echo from mTLS server",
42
+ "timestamp": time.time(),
43
+ "client_cert": self.get_client_cert_info()
44
+ }
45
+ self.wfile.write(json.dumps(response).encode())
46
+ else:
47
+ self.send_response(404)
48
+ self.send_header('Content-type', 'application/json')
49
+ self.end_headers()
50
+ response = {"error": "Not found", "path": self.path}
51
+ self.wfile.write(json.dumps(response).encode())
52
+
53
+ def do_POST(self):
54
+ """Handle POST requests."""
55
+ content_length = int(self.headers.get('Content-Length', 0))
56
+ post_data = self.rfile.read(content_length)
57
+
58
+ try:
59
+ data = json.loads(post_data.decode())
60
+ except json.JSONDecodeError:
61
+ data = {"raw": post_data.decode()}
62
+
63
+ self.send_response(200)
64
+ self.send_header('Content-type', 'application/json')
65
+ self.end_headers()
66
+
67
+ response = {
68
+ "received": data,
69
+ "timestamp": time.time(),
70
+ "client_cert": self.get_client_cert_info(),
71
+ "method": "POST"
72
+ }
73
+ self.wfile.write(json.dumps(response).encode())
74
+
75
+ def get_client_cert_info(self):
76
+ """Get client certificate information."""
77
+ try:
78
+ cert = self.connection.getpeercert()
79
+ if cert:
80
+ return {
81
+ "subject": dict(x[0] for x in cert.get('subject', [])),
82
+ "issuer": dict(x[0] for x in cert.get('issuer', [])),
83
+ "serial": cert.get('serialNumber'),
84
+ "not_before": cert.get('notBefore'),
85
+ "not_after": cert.get('notAfter')
86
+ }
87
+ except Exception:
88
+ pass
89
+ return None
90
+
91
+ def log_message(self, format, *args):
92
+ """Override log message to include client cert info."""
93
+ client_cert = self.get_client_cert_info()
94
+ if client_cert:
95
+ print(f"[{self.address_string()}] {format % args} [Client: {client_cert.get('subject', {}).get('CN', 'Unknown')}]")
96
+ else:
97
+ print(f"[{self.address_string()}] {format % args} [No client cert]")
98
+
99
+ class TestMTLSServer:
100
+ """Test mTLS server for the full application example."""
101
+
102
+ def __init__(self, config_path: str):
103
+ self.config_path = config_path
104
+ self.config = self.load_config()
105
+ self.server = None
106
+ self.thread = None
107
+
108
+ def load_config(self):
109
+ """Load configuration from file."""
110
+ with open(self.config_path, 'r') as f:
111
+ return json.load(f)
112
+
113
+ def create_ssl_context(self):
114
+ """Create SSL context for mTLS."""
115
+ ssl_config = self.config.get('ssl', {})
116
+
117
+ context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
118
+ context.load_cert_chain(
119
+ ssl_config.get('cert_file'),
120
+ ssl_config.get('key_file')
121
+ )
122
+
123
+ # Load CA certificate for client verification
124
+ if ssl_config.get('verify_client', False):
125
+ context.load_verify_locations(ssl_config.get('ca_cert_file'))
126
+ context.verify_mode = ssl.CERT_REQUIRED
127
+
128
+ # Set ciphers and protocols
129
+ if ssl_config.get('ciphers'):
130
+ context.set_ciphers(ssl_config['ciphers'])
131
+
132
+ return context
133
+
134
+ def start_server(self):
135
+ """Start the mTLS server."""
136
+ server_config = self.config.get('server', {})
137
+ host = server_config.get('host', '0.0.0.0')
138
+ port = server_config.get('port', 8443)
139
+
140
+ print(f"🚀 Starting mTLS Test Server")
141
+ print(f"📁 Configuration: {self.config_path}")
142
+ print(f"🌐 Server: {host}:{port}")
143
+ print(f"🔐 mTLS: {'Enabled' if self.config.get('ssl', {}).get('verify_client', False) else 'Disabled'}")
144
+
145
+ # Create server
146
+ self.server = HTTPServer((host, port), TestMTLSHandler)
147
+
148
+ # Configure SSL
149
+ ssl_context = self.create_ssl_context()
150
+ self.server.socket = ssl_context.wrap_socket(
151
+ self.server.socket,
152
+ server_side=True
153
+ )
154
+
155
+ print(f"✅ mTLS Test Server started on {host}:{port}")
156
+ print(f"🔐 SSL Context configured")
157
+ print(f"📜 Available endpoints:")
158
+ print(f" - GET /health - Health check")
159
+ print(f" - GET /echo - Echo test")
160
+ print(f" - POST /echo - Echo with data")
161
+ print(f"\n🛑 Press Ctrl+C to stop the server")
162
+
163
+ try:
164
+ self.server.serve_forever()
165
+ except KeyboardInterrupt:
166
+ print(f"\n🛑 Server stopped by user")
167
+ self.server.shutdown()
168
+
169
+ def start_background(self):
170
+ """Start server in background thread."""
171
+ self.thread = threading.Thread(target=self.start_server, daemon=True)
172
+ self.thread.start()
173
+ time.sleep(1) # Give server time to start
174
+ return self.thread.is_alive()
175
+
176
+ def stop_server(self):
177
+ """Stop the server."""
178
+ if self.server:
179
+ self.server.shutdown()
180
+ if self.thread:
181
+ self.thread.join(timeout=5)
182
+
183
+ def main():
184
+ """Main function."""
185
+ import argparse
186
+
187
+ parser = argparse.ArgumentParser(description="Test mTLS Server")
188
+ parser.add_argument("--config", required=True, help="Configuration file path")
189
+ parser.add_argument("--background", action="store_true", help="Run in background")
190
+ args = parser.parse_args()
191
+
192
+ # Check if config file exists
193
+ config_path = Path(args.config)
194
+ if not config_path.exists():
195
+ print(f"❌ Configuration file not found: {config_path}")
196
+ return 1
197
+
198
+ # Create and start server
199
+ server = TestMTLSServer(str(config_path))
200
+
201
+ if args.background:
202
+ print("🔄 Starting server in background...")
203
+ if server.start_background():
204
+ print("✅ Server started in background")
205
+ print("💡 Use Ctrl+C to stop")
206
+ try:
207
+ while True:
208
+ time.sleep(1)
209
+ except KeyboardInterrupt:
210
+ print("\n🛑 Stopping background server...")
211
+ server.stop_server()
212
+ else:
213
+ print("❌ Failed to start server in background")
214
+ return 1
215
+ else:
216
+ server.start_server()
217
+
218
+ return 0
219
+
220
+ if __name__ == "__main__":
221
+ sys.exit(main())