mcp-proxy-adapter 6.3.5__py3-none-any.whl → 6.3.6__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.
@@ -74,15 +74,24 @@ class ClientSecurityManager:
74
74
  def _create_ssl_config(self) -> SSLConfig:
75
75
  """Create SSL configuration for client connections."""
76
76
  ssl_section = self.security_config.get("ssl", {})
77
+
78
+ # Determine verify_mode based on verify_server setting
79
+ verify_server = ssl_section.get("verify_server", True)
80
+ if verify_server:
81
+ verify_mode = "CERT_REQUIRED"
82
+ check_hostname = True
83
+ else:
84
+ verify_mode = "CERT_NONE"
85
+ check_hostname = False
77
86
 
78
87
  return SSLConfig(
79
88
  enabled=ssl_section.get("enabled", False),
80
89
  cert_file=ssl_section.get("client_cert_file"),
81
90
  key_file=ssl_section.get("client_key_file"),
82
91
  ca_cert_file=ssl_section.get("ca_cert_file"),
83
- verify_mode=ssl_section.get("verify_mode", "CERT_REQUIRED"),
92
+ verify_mode=verify_mode,
84
93
  min_tls_version=ssl_section.get("min_tls_version", "TLSv1.2"),
85
- check_hostname=ssl_section.get("check_hostname", True),
94
+ check_hostname=check_hostname,
86
95
  check_expiry=ssl_section.get("check_expiry", True),
87
96
  )
88
97
 
@@ -107,8 +116,8 @@ class ClientSecurityManager:
107
116
 
108
117
  if server_hostname:
109
118
  # Set server hostname for SNI
110
- context.check_hostname = True
111
- context.verify_mode = ssl.CERT_REQUIRED
119
+ # SSL verification settings are already configured in SSLManager
120
+ # based on verify_server configuration in _create_ssl_config()
112
121
 
113
122
  logger.info(
114
123
  f"Client SSL context created for {server_hostname or 'unknown server'}"
@@ -2,4 +2,4 @@
2
2
  Version information for MCP Proxy Adapter.
3
3
  """
4
4
 
5
- __version__ = "6.3.5"
5
+ __version__ = "6.3.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.3.5
3
+ Version: 6.3.6
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
@@ -4,7 +4,7 @@ mcp_proxy_adapter/config.py,sha256=-7iVS0mUWWKNeao7nqTAFlUD6FcMwRlDkchN7OwYsr0,2
4
4
  mcp_proxy_adapter/custom_openapi.py,sha256=yLle4CntYK9wpivgn9NflZyJhy-YNrmWjJzt0ai5nP0,14672
5
5
  mcp_proxy_adapter/main.py,sha256=Q5WxLVbQ5y9cdpcriFvIuILaxFyPyyxyxQ4OeU3xaYY,3193
6
6
  mcp_proxy_adapter/openapi.py,sha256=2UZOI09ZDRJuBYBjKbMyb2U4uASszoCMD5o_4ktRpvg,13480
7
- mcp_proxy_adapter/version.py,sha256=A4thGMP1TIorVTSMu7oOnJuatKeLCbedU_xenofVtqM,74
7
+ mcp_proxy_adapter/version.py,sha256=Gn1VObxc75DJfaUYzoY-mCWYCASonlitN683s_sCoZQ,74
8
8
  mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  mcp_proxy_adapter/api/app.py,sha256=22NIDGo6pGkOZnvBWeKv_-RIRye4YaYkIskVGIsCCMs,28600
10
10
  mcp_proxy_adapter/api/handlers.py,sha256=iyFGoEuUS1wxbV1ELA0zmaxIyQR7j4zw-4MrD-uIO6E,8294
@@ -59,7 +59,7 @@ mcp_proxy_adapter/core/auth_validator.py,sha256=q8TNkdolvP-gM6Bvecc6nrVG9al5J31p
59
59
  mcp_proxy_adapter/core/certificate_utils.py,sha256=yeDwi-j42CxK_g-r5_ragGFY_HdSgDfTWHVUjDHF6nI,38480
60
60
  mcp_proxy_adapter/core/client.py,sha256=qIbPl8prEwK2U65kl-vGJW2_imo1E4i6HxG_VpPeWpQ,21168
61
61
  mcp_proxy_adapter/core/client_manager.py,sha256=yD8HZJlOwmDbVU49YfzSbh1XZ-Vib8qfcLVAaH03Jdg,8832
62
- mcp_proxy_adapter/core/client_security.py,sha256=I0yjWbVFyR8Im1avatXuBApFeSZoG6iJJHArMhF4A2Q,13053
62
+ mcp_proxy_adapter/core/client_security.py,sha256=3LIhZl9uUW9zXSllwX3RQutR583T_uIVluibEcwAr1A,13374
63
63
  mcp_proxy_adapter/core/config_converter.py,sha256=Wnnsrbw7DxtgDfLG-IyyzK-hkKu0_1yp7-7dW87tu_4,17422
64
64
  mcp_proxy_adapter/core/config_validator.py,sha256=M_iQqskKk5VfziNkXTJwjU97vEBLNSsXIqtpTQKHAcA,9644
65
65
  mcp_proxy_adapter/core/crl_utils.py,sha256=Jnwq2UN52IoCDZCwByRP3XNMOJexftb-mVaH6zes6Fc,11706
@@ -135,9 +135,10 @@ mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py,sha256=hU
135
135
  mcp_proxy_adapter/schemas/base_schema.json,sha256=v9G9cGMd4dRhCZsOQ_FMqOi5VFyVbI6Cf3fyIvOT9dc,2881
136
136
  mcp_proxy_adapter/schemas/openapi_schema.json,sha256=C3yLkwmDsvnLW9B5gnKKdBGl4zxkeU-rEmjTrNVsQU0,8405
137
137
  mcp_proxy_adapter/utils/config_generator.py,sha256=UXxuxxAyKTesAS3DOofQ26e20v771inA7EfBV8PZD1c,47543
138
- mcp_proxy_adapter-6.3.5.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
139
- mcp_proxy_adapter-6.3.5.dist-info/METADATA,sha256=xuV_AjVe_gnk1r-mNElVj9TvgyzfBpr44DIT_3ZWgF0,22347
140
- mcp_proxy_adapter-6.3.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
141
- mcp_proxy_adapter-6.3.5.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
142
- mcp_proxy_adapter-6.3.5.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
143
- mcp_proxy_adapter-6.3.5.dist-info/RECORD,,
138
+ mcp_proxy_adapter-6.3.6.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
139
+ mcp_proxy_adapter_issue_package/demonstrate_issue.py,sha256=NDyiWSjQHly4ji1sB4ZqdmOFyZlPQ4Id80dTrRwcmoE,7736
140
+ mcp_proxy_adapter-6.3.6.dist-info/METADATA,sha256=eaKlcNLOyaQ2QBKtFYen8ugwyOcYnfFqq4-2b7lz4vc,22347
141
+ mcp_proxy_adapter-6.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
142
+ mcp_proxy_adapter-6.3.6.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
143
+ mcp_proxy_adapter-6.3.6.dist-info/top_level.txt,sha256=CHk-Mc-AxjO-tRheegA2qLiQnU4vZRnxuTF81So6SAc,50
144
+ mcp_proxy_adapter-6.3.6.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ mcp_proxy_adapter
2
+ mcp_proxy_adapter_issue_package
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Demonstration script showing the mcp_proxy_adapter SSL verification issue.
4
+ This script reproduces the problem where verify_server: false is ignored.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+ import ssl
10
+ import asyncio
11
+ import aiohttp
12
+ import logging
13
+ from pathlib import Path
14
+
15
+ # Setup logging
16
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
+ logger = logging.getLogger(__name__)
18
+
19
+ class MockSSLConfig:
20
+ """Mock SSL configuration to demonstrate the issue."""
21
+
22
+ def __init__(self, verify_server=True):
23
+ self.verify_server = verify_server
24
+ self.ca_cert_file = "certs/mtls/truststore.pem"
25
+ self.client_cert_file = "certs/mtls/client/embedding-service.pem"
26
+ self.client_key_file = "certs/mtls/client/embedding-service.key"
27
+
28
+ def create_client_ssl_context_broken(ssl_config: MockSSLConfig) -> ssl.SSLContext:
29
+ """
30
+ BROKEN: This is how mcp_proxy_adapter currently works.
31
+ It hardcodes CERT_REQUIRED, ignoring the verify_server setting.
32
+ """
33
+ logger.info("🔴 Creating SSL context (BROKEN - current mcp_proxy_adapter behavior)")
34
+ logger.info(f" Configuration: verify_server={ssl_config.verify_server}")
35
+
36
+ try:
37
+ ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
38
+
39
+ # Load CA certificate if provided
40
+ if ssl_config.ca_cert_file and Path(ssl_config.ca_cert_file).exists():
41
+ ssl_context.load_verify_locations(ssl_config.ca_cert_file)
42
+ logger.info(f" ✅ Loaded CA certificate: {ssl_config.ca_cert_file}")
43
+
44
+ # Load client certificate if provided
45
+ if (ssl_config.client_cert_file and ssl_config.client_key_file and
46
+ Path(ssl_config.client_cert_file).exists() and Path(ssl_config.client_key_file).exists()):
47
+ ssl_context.load_cert_chain(
48
+ ssl_config.client_cert_file,
49
+ ssl_config.client_key_file
50
+ )
51
+ logger.info(f" ✅ Loaded client certificate: {ssl_config.client_cert_file}")
52
+
53
+ # PROBLEM: This line hardcodes CERT_REQUIRED, ignoring configuration
54
+ ssl_context.verify_mode = ssl.CERT_REQUIRED
55
+ logger.info(" ❌ HARDCODED: ssl_context.verify_mode = ssl.CERT_REQUIRED")
56
+ logger.info(" ❌ IGNORES: verify_server=False configuration!")
57
+
58
+ return ssl_context
59
+ except Exception as e:
60
+ logger.error(f" ❌ Failed to create SSL context: {e}")
61
+ return ssl.create_default_context()
62
+
63
+ def create_client_ssl_context_fixed(ssl_config: MockSSLConfig) -> ssl.SSLContext:
64
+ """
65
+ FIXED: This is how mcp_proxy_adapter should work.
66
+ It respects the verify_server configuration setting.
67
+ """
68
+ logger.info("🟢 Creating SSL context (FIXED - proposed solution)")
69
+ logger.info(f" Configuration: verify_server={ssl_config.verify_server}")
70
+
71
+ try:
72
+ ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
73
+
74
+ # Load CA certificate if provided
75
+ if ssl_config.ca_cert_file and Path(ssl_config.ca_cert_file).exists():
76
+ ssl_context.load_verify_locations(ssl_config.ca_cert_file)
77
+ logger.info(f" ✅ Loaded CA certificate: {ssl_config.ca_cert_file}")
78
+
79
+ # Load client certificate if provided
80
+ if (ssl_config.client_cert_file and ssl_config.client_key_file and
81
+ Path(ssl_config.client_cert_file).exists() and Path(ssl_config.client_key_file).exists()):
82
+ ssl_context.load_cert_chain(
83
+ ssl_config.client_cert_file,
84
+ ssl_config.client_key_file
85
+ )
86
+ logger.info(f" ✅ Loaded client certificate: {ssl_config.client_cert_file}")
87
+
88
+ # FIX: Respect the verify_server configuration
89
+ if not ssl_config.verify_server:
90
+ ssl_context.check_hostname = False # Must be set BEFORE verify_mode
91
+ ssl_context.verify_mode = ssl.CERT_NONE
92
+ logger.info(" ✅ RESPECTS: ssl_context.check_hostname = False")
93
+ logger.info(" ✅ RESPECTS: ssl_context.verify_mode = ssl.CERT_NONE (verify_server=False)")
94
+ else:
95
+ ssl_context.verify_mode = ssl.CERT_REQUIRED
96
+ logger.info(" ✅ RESPECTS: ssl_context.verify_mode = ssl.CERT_REQUIRED (verify_server=True)")
97
+
98
+ return ssl_context
99
+ except Exception as e:
100
+ logger.error(f" ❌ Failed to create SSL context: {e}")
101
+ return ssl.create_default_context()
102
+
103
+ async def test_connection(ssl_context: ssl.SSLContext, url: str, description: str):
104
+ """Test connection with the given SSL context."""
105
+ logger.info(f"\n🧪 Testing connection: {description}")
106
+ logger.info(f" URL: {url}")
107
+
108
+ try:
109
+ connector = aiohttp.TCPConnector(ssl=ssl_context)
110
+ async with aiohttp.ClientSession(connector=connector) as session:
111
+ async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as response:
112
+ logger.info(f" ✅ SUCCESS: HTTP {response.status}")
113
+ return True
114
+ except ssl.SSLCertVerificationError as e:
115
+ logger.error(f" ❌ SSL VERIFICATION ERROR: {e}")
116
+ return False
117
+ except Exception as e:
118
+ logger.error(f" ❌ CONNECTION ERROR: {e}")
119
+ return False
120
+
121
+ async def main():
122
+ """Main demonstration function."""
123
+ logger.info("🚀 mcp_proxy_adapter SSL Verification Issue Demonstration")
124
+ logger.info("=" * 70)
125
+
126
+ # Test URL with self-signed certificate
127
+ test_url = "https://127.0.0.1:3004/health"
128
+
129
+ # Configuration with verify_server=False (should be respected)
130
+ config = MockSSLConfig(verify_server=False)
131
+
132
+ logger.info(f"\n📋 Test Configuration:")
133
+ logger.info(f" URL: {test_url}")
134
+ logger.info(f" verify_server: {config.verify_server}")
135
+ logger.info(f" CA cert: {config.ca_cert_file}")
136
+ logger.info(f" Client cert: {config.client_cert_file}")
137
+
138
+ # Test 1: Current broken behavior
139
+ logger.info(f"\n" + "="*50)
140
+ logger.info("TEST 1: Current mcp_proxy_adapter behavior (BROKEN)")
141
+ logger.info("="*50)
142
+
143
+ broken_ssl_context = create_client_ssl_context_broken(config)
144
+ broken_result = await test_connection(broken_ssl_context, test_url, "BROKEN - ignores verify_server=False")
145
+
146
+ # Test 2: Proposed fixed behavior
147
+ logger.info(f"\n" + "="*50)
148
+ logger.info("TEST 2: Proposed fixed behavior")
149
+ logger.info("="*50)
150
+
151
+ fixed_ssl_context = create_client_ssl_context_fixed(config)
152
+ fixed_result = await test_connection(fixed_ssl_context, test_url, "FIXED - respects verify_server=False")
153
+
154
+ # Summary
155
+ logger.info(f"\n" + "="*50)
156
+ logger.info("SUMMARY")
157
+ logger.info("="*50)
158
+ logger.info(f"🔴 Current behavior (broken): {'FAILED' if not broken_result else 'SUCCESS'}")
159
+ logger.info(f"🟢 Proposed fix: {'SUCCESS' if fixed_result else 'FAILED'}")
160
+
161
+ if not broken_result and fixed_result:
162
+ logger.info("\n✅ DEMONSTRATION SUCCESSFUL!")
163
+ logger.info(" The issue is confirmed: verify_server=False is ignored")
164
+ logger.info(" The proposed fix works: verify_server=False is respected")
165
+ elif broken_result and not fixed_result:
166
+ logger.info("\n❓ UNEXPECTED RESULT")
167
+ logger.info(" Both approaches failed - may be a different issue")
168
+ else:
169
+ logger.info("\n❓ INCONCLUSIVE")
170
+ logger.info(" Results don't clearly demonstrate the issue")
171
+
172
+ if __name__ == "__main__":
173
+ try:
174
+ asyncio.run(main())
175
+ except KeyboardInterrupt:
176
+ logger.info("\n🛑 Demonstration interrupted by user")
177
+ except Exception as e:
178
+ logger.error(f"\n❌ Demonstration error: {e}")
@@ -1 +0,0 @@
1
- mcp_proxy_adapter