mcp-proxy-adapter 6.3.30__py3-none-any.whl → 6.4.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_proxy_adapter/api/middleware/unified_security.py +19 -9
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +61 -62
- mcp_proxy_adapter/commands/dependency_manager.py +46 -29
- mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
- mcp_proxy_adapter/examples/full_application/roles.json +21 -0
- mcp_proxy_adapter/examples/generate_comprehensive_config.py +177 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +11 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +105 -134
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.3.30.dist-info → mcp_proxy_adapter-6.4.1.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-6.3.30.dist-info → mcp_proxy_adapter-6.4.1.dist-info}/RECORD +14 -12
- mcp_proxy_adapter/examples/setup_test_environment_old.py +0 -316
- {mcp_proxy_adapter-6.3.30.dist-info → mcp_proxy_adapter-6.4.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.30.dist-info → mcp_proxy_adapter-6.4.1.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.30.dist-info → mcp_proxy_adapter-6.4.1.dist-info}/top_level.txt +0 -0
@@ -64,15 +64,25 @@ class UnifiedSecurityMiddleware(BaseHTTPMiddleware):
|
|
64
64
|
# Create security integration
|
65
65
|
try:
|
66
66
|
security_config = config.get("security", {})
|
67
|
-
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
|
68
|
+
# Check if permissions are enabled - only use mcp_security_framework if needed
|
69
|
+
permissions_config = security_config.get("permissions", {})
|
70
|
+
permissions_enabled = permissions_config.get("enabled", False)
|
71
|
+
|
72
|
+
if permissions_enabled:
|
73
|
+
self.security_integration = create_security_integration(security_config)
|
74
|
+
# Use framework's FastAPI middleware
|
75
|
+
self.framework_middleware = (
|
76
|
+
self.security_integration.security_manager.create_fastapi_middleware()
|
77
|
+
)
|
78
|
+
logger.info("Using mcp_security_framework FastAPI middleware")
|
79
|
+
# IMPORTANT: Don't replace self.app! This breaks the middleware chain.
|
80
|
+
# Instead, store the framework middleware for use in dispatch method.
|
81
|
+
logger.info("Framework middleware will be used in dispatch method")
|
82
|
+
else:
|
83
|
+
logger.info("Permissions disabled, skipping mcp_security_framework integration")
|
84
|
+
self.security_integration = None
|
85
|
+
self.framework_middleware = None
|
76
86
|
except Exception as e:
|
77
87
|
logger.error(f"Security framework integration failed: {e}")
|
78
88
|
# Instead of raising error, log warning and continue without security
|
@@ -53,69 +53,68 @@ class UserInfoMiddleware(BaseHTTPMiddleware):
|
|
53
53
|
try:
|
54
54
|
# Get API keys configuration
|
55
55
|
security_config = config.get("security", {})
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
# Create AuthConfig for mcp_security_framework
|
63
|
-
mcp_auth_config = AuthConfig(
|
64
|
-
enabled=True,
|
65
|
-
methods=["api_key"],
|
66
|
-
api_keys=auth_config.get("api_keys", {}),
|
67
|
-
)
|
68
|
-
|
69
|
-
# Initialize PermissionManager only if permissions are enabled
|
70
|
-
if permissions_enabled:
|
71
|
-
# Create PermissionConfig for mcp_security_framework
|
72
|
-
roles_file = permissions_config.get("roles_file")
|
73
|
-
if roles_file is None:
|
74
|
-
logger.warning("⚠️ Permissions enabled but no roles_file specified, using default configuration")
|
75
|
-
roles_file = None
|
76
|
-
|
77
|
-
mcp_permission_config = PermissionConfig(
|
78
|
-
roles_file=roles_file,
|
79
|
-
default_role=permissions_config.get("default_role", "guest"),
|
80
|
-
admin_role=permissions_config.get("admin_role", "admin"),
|
81
|
-
role_hierarchy=permissions_config.get("role_hierarchy", {}),
|
82
|
-
permission_cache_enabled=permissions_config.get(
|
83
|
-
"permission_cache_enabled", True
|
84
|
-
),
|
85
|
-
permission_cache_ttl=permissions_config.get(
|
86
|
-
"permission_cache_ttl", 300
|
87
|
-
),
|
88
|
-
wildcard_permissions=permissions_config.get(
|
89
|
-
"wildcard_permissions", False
|
90
|
-
),
|
91
|
-
strict_mode=permissions_config.get("strict_mode", True),
|
92
|
-
roles=permissions_config.get("roles", {}),
|
93
|
-
)
|
94
|
-
|
95
|
-
# Initialize PermissionManager first
|
96
|
-
self.permission_manager = PermissionManager(mcp_permission_config)
|
56
|
+
|
57
|
+
# Check if security is enabled
|
58
|
+
security_enabled = security_config.get("enabled", False)
|
59
|
+
if not security_enabled:
|
60
|
+
logger.info("ℹ️ Security disabled in configuration, using basic auth")
|
61
|
+
self._security_available = False
|
97
62
|
else:
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
63
|
+
auth_config = security_config.get("auth", {})
|
64
|
+
permissions_config = security_config.get("permissions", {})
|
65
|
+
|
66
|
+
# Check if permissions are enabled
|
67
|
+
permissions_enabled = permissions_config.get("enabled", False)
|
68
|
+
|
69
|
+
# Only use mcp_security_framework if permissions are enabled
|
70
|
+
if permissions_enabled:
|
71
|
+
# Create AuthConfig for mcp_security_framework
|
72
|
+
mcp_auth_config = AuthConfig(
|
73
|
+
enabled=True,
|
74
|
+
methods=["api_key"],
|
75
|
+
api_keys=auth_config.get("api_keys", {}),
|
76
|
+
)
|
77
|
+
|
78
|
+
# Create PermissionConfig for mcp_security_framework
|
79
|
+
roles_file = permissions_config.get("roles_file")
|
80
|
+
if roles_file is None:
|
81
|
+
logger.warning("⚠️ Permissions enabled but no roles_file specified, using default configuration")
|
82
|
+
roles_file = None
|
83
|
+
|
84
|
+
mcp_permission_config = PermissionConfig(
|
85
|
+
roles_file=roles_file,
|
86
|
+
default_role=permissions_config.get("default_role", "guest"),
|
87
|
+
admin_role=permissions_config.get("admin_role", "admin"),
|
88
|
+
role_hierarchy=permissions_config.get("role_hierarchy", {}),
|
89
|
+
permission_cache_enabled=permissions_config.get(
|
90
|
+
"permission_cache_enabled", True
|
91
|
+
),
|
92
|
+
permission_cache_ttl=permissions_config.get(
|
93
|
+
"permission_cache_ttl", 300
|
94
|
+
),
|
95
|
+
wildcard_permissions=permissions_config.get(
|
96
|
+
"wildcard_permissions", False
|
97
|
+
),
|
98
|
+
strict_mode=permissions_config.get("strict_mode", True),
|
99
|
+
roles=permissions_config.get("roles", {}),
|
100
|
+
)
|
101
|
+
|
102
|
+
# Initialize PermissionManager first
|
103
|
+
self.permission_manager = PermissionManager(mcp_permission_config)
|
104
|
+
|
105
|
+
# Initialize AuthManager with permission_manager
|
106
|
+
self.auth_manager = AuthManager(
|
107
|
+
mcp_auth_config, self.permission_manager
|
108
|
+
)
|
109
|
+
logger.info(
|
110
|
+
"✅ User info middleware initialized with " "mcp_security_framework"
|
111
|
+
)
|
112
|
+
else:
|
113
|
+
# When permissions are disabled, use basic auth without mcp_security_framework
|
114
|
+
logger.info("ℹ️ Permissions disabled, using basic token auth without mcp_security_framework")
|
115
|
+
self._security_available = False
|
116
|
+
# Initialize api_keys for basic auth
|
117
|
+
self.api_keys = auth_config.get("api_keys", {})
|
119
118
|
except Exception as e:
|
120
119
|
logger.warning(f"⚠️ Failed to initialize AuthManager: {e}")
|
121
120
|
self._security_available = False
|
@@ -3,15 +3,26 @@ Dependency management system for remote plugins.
|
|
3
3
|
|
4
4
|
This module handles automatic installation and verification of plugin dependencies
|
5
5
|
using pip and other package management tools.
|
6
|
+
|
7
|
+
Author: Vasiliy Zdanovskiy
|
8
|
+
email: vasilyvz@gmail.com
|
6
9
|
"""
|
7
10
|
|
8
11
|
import subprocess
|
9
12
|
import sys
|
10
13
|
import importlib
|
11
|
-
import
|
12
|
-
from typing import List, Dict, Any, Optional, Tuple
|
14
|
+
from typing import List, Dict, Any, Tuple
|
13
15
|
from pathlib import Path
|
14
16
|
|
17
|
+
try: # Python 3.8+
|
18
|
+
from importlib import metadata as importlib_metadata # type: ignore
|
19
|
+
except Exception: # pragma: no cover - very old Python fallback
|
20
|
+
import importlib_metadata # type: ignore
|
21
|
+
|
22
|
+
from packaging.requirements import Requirement
|
23
|
+
from packaging.specifiers import SpecifierSet
|
24
|
+
from packaging.version import Version, InvalidVersion
|
25
|
+
|
15
26
|
from mcp_proxy_adapter.core.logging import logger
|
16
27
|
|
17
28
|
|
@@ -28,9 +39,15 @@ class DependencyManager:
|
|
28
39
|
def _load_installed_packages(self) -> None:
|
29
40
|
"""Load list of currently installed packages."""
|
30
41
|
try:
|
31
|
-
|
32
|
-
for dist in
|
33
|
-
|
42
|
+
self._installed_packages.clear()
|
43
|
+
for dist in importlib_metadata.distributions():
|
44
|
+
try:
|
45
|
+
name = dist.metadata.get("Name") or dist.metadata.get("name")
|
46
|
+
version = dist.version
|
47
|
+
if name and version:
|
48
|
+
self._installed_packages[name.lower()] = version
|
49
|
+
except Exception:
|
50
|
+
continue
|
34
51
|
except Exception as e:
|
35
52
|
logger.warning(f"Failed to load installed packages: {e}")
|
36
53
|
|
@@ -71,32 +88,32 @@ class DependencyManager:
|
|
71
88
|
Returns:
|
72
89
|
True if dependency is satisfied, False otherwise
|
73
90
|
"""
|
74
|
-
#
|
91
|
+
# Parse requirement (handles version specifiers)
|
75
92
|
try:
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
93
|
+
req = Requirement(dependency)
|
94
|
+
except Exception:
|
95
|
+
# Fallback: treat as importable module name
|
96
|
+
try:
|
97
|
+
importlib.import_module(dependency)
|
98
|
+
return True
|
99
|
+
except ImportError:
|
100
|
+
return False
|
80
101
|
|
81
|
-
# Check
|
102
|
+
# Check installation by distribution name
|
82
103
|
try:
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
pass
|
104
|
+
installed_version = importlib_metadata.version(req.name)
|
105
|
+
except importlib_metadata.PackageNotFoundError:
|
106
|
+
return False
|
87
107
|
|
88
|
-
#
|
89
|
-
|
90
|
-
dependency.split("==")[0]
|
91
|
-
.split(">=")[0]
|
92
|
-
.split("<=")[0]
|
93
|
-
.split("!=")[0]
|
94
|
-
.split("~=")[0]
|
95
|
-
)
|
96
|
-
if dep_name.lower() in self._installed_packages:
|
108
|
+
# If no specifier, any installed version satisfies
|
109
|
+
if not req.specifier:
|
97
110
|
return True
|
98
111
|
|
99
|
-
|
112
|
+
try:
|
113
|
+
return Version(installed_version) in req.specifier
|
114
|
+
except InvalidVersion:
|
115
|
+
# If version parsing fails, fallback to string comparison via specifier
|
116
|
+
return req.specifier.contains(installed_version, prereleases=True)
|
100
117
|
|
101
118
|
def install_dependencies(
|
102
119
|
self, dependencies: List[str], user_install: bool = False
|
@@ -216,7 +233,7 @@ class DependencyManager:
|
|
216
233
|
Returns:
|
217
234
|
Dictionary with dependency information
|
218
235
|
"""
|
219
|
-
info = {
|
236
|
+
info: Dict[str, Any] = {
|
220
237
|
"name": dependency,
|
221
238
|
"installed": False,
|
222
239
|
"version": None,
|
@@ -225,10 +242,10 @@ class DependencyManager:
|
|
225
242
|
|
226
243
|
# Check if it's installed
|
227
244
|
try:
|
228
|
-
|
245
|
+
version = importlib_metadata.version(dependency)
|
229
246
|
info["installed"] = True
|
230
|
-
info["version"] =
|
231
|
-
except
|
247
|
+
info["version"] = version
|
248
|
+
except importlib_metadata.PackageNotFoundError:
|
232
249
|
pass
|
233
250
|
|
234
251
|
# Check if it's importable
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"roles": {
|
3
|
+
"admin": {
|
4
|
+
"permissions": ["*"],
|
5
|
+
"description": "Administrator with full access"
|
6
|
+
},
|
7
|
+
"user": {
|
8
|
+
"permissions": ["read", "write"],
|
9
|
+
"description": "Regular user with read/write access"
|
10
|
+
},
|
11
|
+
"readonly": {
|
12
|
+
"permissions": ["read"],
|
13
|
+
"description": "Read-only user"
|
14
|
+
}
|
15
|
+
},
|
16
|
+
"user_roles": {
|
17
|
+
"admin": "admin",
|
18
|
+
"user": "user",
|
19
|
+
"readonly": "readonly"
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"roles": {
|
3
|
+
"admin": {
|
4
|
+
"permissions": ["*"],
|
5
|
+
"description": "Administrator with full access"
|
6
|
+
},
|
7
|
+
"user": {
|
8
|
+
"permissions": ["read", "write"],
|
9
|
+
"description": "Regular user with read/write access"
|
10
|
+
},
|
11
|
+
"readonly": {
|
12
|
+
"permissions": ["read"],
|
13
|
+
"description": "Read-only user"
|
14
|
+
}
|
15
|
+
},
|
16
|
+
"user_roles": {
|
17
|
+
"admin": "admin",
|
18
|
+
"user": "user",
|
19
|
+
"readonly": "readonly"
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Author: Vasiliy Zdanovskiy
|
4
|
+
email: vasilyvz@gmail.com
|
5
|
+
Script for generating comprehensive HTTP configuration for MCP Proxy Adapter.
|
6
|
+
Generates single comprehensive configuration with all features enabled.
|
7
|
+
"""
|
8
|
+
import json
|
9
|
+
import os
|
10
|
+
import argparse
|
11
|
+
import uuid
|
12
|
+
from typing import Dict, Any
|
13
|
+
|
14
|
+
|
15
|
+
def generate_comprehensive_http_config(
|
16
|
+
port: int = 20001,
|
17
|
+
roles_file: str = "configs/roles.json",
|
18
|
+
) -> Dict[str, Any]:
|
19
|
+
"""Generate comprehensive HTTP configuration with all features."""
|
20
|
+
return {
|
21
|
+
"uuid": str(uuid.uuid4()),
|
22
|
+
"server": {
|
23
|
+
"host": "127.0.0.1",
|
24
|
+
"port": port,
|
25
|
+
"debug": False,
|
26
|
+
"log_level": "INFO",
|
27
|
+
"workers": 1,
|
28
|
+
"reload": False
|
29
|
+
},
|
30
|
+
"ssl": {
|
31
|
+
"enabled": False
|
32
|
+
},
|
33
|
+
"security": {
|
34
|
+
"enabled": True,
|
35
|
+
"auth": {
|
36
|
+
"enabled": True,
|
37
|
+
"methods": [
|
38
|
+
"api_key"
|
39
|
+
],
|
40
|
+
"api_keys": {
|
41
|
+
"admin-token-123": "admin",
|
42
|
+
"user-token-456": "user",
|
43
|
+
"readonly-token-789": "readonly",
|
44
|
+
"guest-token-abc": "guest",
|
45
|
+
"proxy-token-def": "proxy"
|
46
|
+
}
|
47
|
+
},
|
48
|
+
"permissions": {
|
49
|
+
"enabled": True,
|
50
|
+
"roles_file": roles_file
|
51
|
+
}
|
52
|
+
},
|
53
|
+
"registration": {
|
54
|
+
"enabled": True,
|
55
|
+
"url": "http://127.0.0.1:3004/proxy",
|
56
|
+
"name": "comprehensive_http_adapter",
|
57
|
+
"capabilities": [
|
58
|
+
"http",
|
59
|
+
"token_auth",
|
60
|
+
"roles",
|
61
|
+
"registration",
|
62
|
+
"heartbeat"
|
63
|
+
],
|
64
|
+
"retry_count": 3,
|
65
|
+
"retry_delay": 5,
|
66
|
+
"heartbeat": {
|
67
|
+
"enabled": True,
|
68
|
+
"interval": 30
|
69
|
+
}
|
70
|
+
},
|
71
|
+
"protocols": {
|
72
|
+
"enabled": True,
|
73
|
+
"allowed_protocols": [
|
74
|
+
"http"
|
75
|
+
]
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
|
80
|
+
def generate_roles_config() -> Dict[str, Any]:
|
81
|
+
"""Generate comprehensive roles configuration."""
|
82
|
+
return {
|
83
|
+
"admin": {
|
84
|
+
"description": "Full administrative access",
|
85
|
+
"permissions": [
|
86
|
+
"read",
|
87
|
+
"write",
|
88
|
+
"execute",
|
89
|
+
"delete",
|
90
|
+
"admin"
|
91
|
+
],
|
92
|
+
"inherits": []
|
93
|
+
},
|
94
|
+
"user": {
|
95
|
+
"description": "Standard user access",
|
96
|
+
"permissions": [
|
97
|
+
"read",
|
98
|
+
"write",
|
99
|
+
"execute"
|
100
|
+
],
|
101
|
+
"inherits": []
|
102
|
+
},
|
103
|
+
"readonly": {
|
104
|
+
"description": "Read-only access",
|
105
|
+
"permissions": [
|
106
|
+
"read"
|
107
|
+
],
|
108
|
+
"inherits": []
|
109
|
+
},
|
110
|
+
"guest": {
|
111
|
+
"description": "Limited guest access",
|
112
|
+
"permissions": [
|
113
|
+
"read"
|
114
|
+
],
|
115
|
+
"inherits": []
|
116
|
+
},
|
117
|
+
"proxy": {
|
118
|
+
"description": "Proxy registration access",
|
119
|
+
"permissions": [
|
120
|
+
"read",
|
121
|
+
"register",
|
122
|
+
"heartbeat"
|
123
|
+
],
|
124
|
+
"inherits": []
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
|
129
|
+
def main():
|
130
|
+
"""Generate comprehensive configuration."""
|
131
|
+
parser = argparse.ArgumentParser(description="Generate comprehensive HTTP configuration")
|
132
|
+
parser.add_argument(
|
133
|
+
"--output-dir",
|
134
|
+
default="configs",
|
135
|
+
help="Output directory for configuration files"
|
136
|
+
)
|
137
|
+
parser.add_argument(
|
138
|
+
"--port",
|
139
|
+
type=int,
|
140
|
+
default=20001,
|
141
|
+
help="Server port"
|
142
|
+
)
|
143
|
+
|
144
|
+
args = parser.parse_args()
|
145
|
+
|
146
|
+
# Create output directory
|
147
|
+
os.makedirs(args.output_dir, exist_ok=True)
|
148
|
+
|
149
|
+
# Generate comprehensive HTTP configuration
|
150
|
+
config = generate_comprehensive_http_config(port=args.port)
|
151
|
+
config_file = os.path.join(args.output_dir, "comprehensive_http.json")
|
152
|
+
|
153
|
+
with open(config_file, 'w') as f:
|
154
|
+
json.dump(config, f, indent=2)
|
155
|
+
|
156
|
+
print(f"Generated: {config_file}")
|
157
|
+
|
158
|
+
# Generate roles configuration
|
159
|
+
roles = generate_roles_config()
|
160
|
+
roles_file = os.path.join(args.output_dir, "roles.json")
|
161
|
+
|
162
|
+
with open(roles_file, 'w') as f:
|
163
|
+
json.dump(roles, f, indent=2)
|
164
|
+
|
165
|
+
print(f"Generated: {roles_file}")
|
166
|
+
|
167
|
+
print(f"\nGenerated comprehensive configuration in {args.output_dir}/")
|
168
|
+
print("Configuration includes:")
|
169
|
+
print("- HTTP server with token authentication")
|
170
|
+
print("- Role-based permissions")
|
171
|
+
print("- Proxy registration")
|
172
|
+
print("- Heartbeat monitoring")
|
173
|
+
print("- 5 predefined tokens with roles")
|
174
|
+
|
175
|
+
|
176
|
+
if __name__ == "__main__":
|
177
|
+
main()
|
@@ -8,6 +8,7 @@ Generates 6 different configuration types for testing various security scenarios
|
|
8
8
|
import json
|
9
9
|
import os
|
10
10
|
import argparse
|
11
|
+
import uuid
|
11
12
|
from typing import Dict, Any
|
12
13
|
|
13
14
|
|
@@ -16,6 +17,7 @@ def generate_http_simple_config(
|
|
16
17
|
) -> Dict[str, Any]:
|
17
18
|
"""Generate HTTP configuration without authorization."""
|
18
19
|
return {
|
20
|
+
"uuid": str(uuid.uuid4()),
|
19
21
|
"server": {"host": "127.0.0.1", "port": port},
|
20
22
|
"ssl": {"enabled": False},
|
21
23
|
"security": {"enabled": False},
|
@@ -47,6 +49,7 @@ def generate_http_token_config(
|
|
47
49
|
) -> Dict[str, Any]:
|
48
50
|
"""Generate HTTP configuration with token authorization."""
|
49
51
|
return {
|
52
|
+
"uuid": str(uuid.uuid4()),
|
50
53
|
"server": {"host": "127.0.0.1", "port": port},
|
51
54
|
"ssl": {"enabled": False},
|
52
55
|
"security": {
|
@@ -83,6 +86,7 @@ def generate_https_simple_config(
|
|
83
86
|
) -> Dict[str, Any]:
|
84
87
|
"""Generate HTTPS configuration without client certificate verification and authorization."""
|
85
88
|
return {
|
89
|
+
"uuid": str(uuid.uuid4()),
|
86
90
|
"server": {"host": "127.0.0.1", "port": port},
|
87
91
|
"ssl": {
|
88
92
|
"enabled": True,
|
@@ -108,6 +112,7 @@ def generate_https_token_config(
|
|
108
112
|
) -> Dict[str, Any]:
|
109
113
|
"""Generate HTTPS configuration without client certificate verification with token authorization."""
|
110
114
|
return {
|
115
|
+
"uuid": str(uuid.uuid4()),
|
111
116
|
"server": {"host": "127.0.0.1", "port": port},
|
112
117
|
"ssl": {
|
113
118
|
"enabled": True,
|
@@ -147,12 +152,15 @@ def generate_mtls_no_roles_config(
|
|
147
152
|
) -> Dict[str, Any]:
|
148
153
|
"""Generate mTLS configuration without roles."""
|
149
154
|
return {
|
155
|
+
"uuid": str(uuid.uuid4()),
|
150
156
|
"server": {"host": "127.0.0.1", "port": port},
|
151
157
|
"ssl": {
|
152
158
|
"enabled": True,
|
153
159
|
"cert_file": f"{certs_dir}/localhost_server.crt",
|
154
160
|
"key_file": f"{keys_dir}/localhost_server.key",
|
155
161
|
"ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
|
162
|
+
"client_cert_file": f"{certs_dir}/admin_cert.pem",
|
163
|
+
"client_key_file": f"{certs_dir}/admin_key.pem",
|
156
164
|
"verify_client": True,
|
157
165
|
"client_cert_required": True,
|
158
166
|
},
|
@@ -174,12 +182,15 @@ def generate_mtls_with_roles_config(
|
|
174
182
|
) -> Dict[str, Any]:
|
175
183
|
"""Generate mTLS configuration with roles."""
|
176
184
|
return {
|
185
|
+
"uuid": str(uuid.uuid4()),
|
177
186
|
"server": {"host": "127.0.0.1", "port": port},
|
178
187
|
"ssl": {
|
179
188
|
"enabled": True,
|
180
189
|
"cert_file": f"{certs_dir}/localhost_server.crt",
|
181
190
|
"key_file": f"{keys_dir}/localhost_server.key",
|
182
191
|
"ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
|
192
|
+
"client_cert_file": f"{certs_dir}/admin_cert.pem",
|
193
|
+
"client_key_file": f"{certs_dir}/admin_key.pem",
|
183
194
|
"verify_client": True,
|
184
195
|
},
|
185
196
|
"registration": {
|
@@ -618,135 +618,66 @@ def generate_enhanced_configurations(output_dir: Path) -> None:
|
|
618
618
|
|
619
619
|
validator = ConfigurationValidator()
|
620
620
|
|
621
|
-
#
|
621
|
+
# Single comprehensive HTTP configuration with all features
|
622
622
|
configs = {
|
623
|
-
"
|
624
|
-
"server": {"host": "0.0.0.0", "port": 8000},
|
625
|
-
"protocols": {"enabled": False},
|
626
|
-
"security": {"ssl": {"enabled": False}},
|
627
|
-
"logging": {"level": "DEBUG"},
|
628
|
-
},
|
629
|
-
"production_https.json": {
|
630
|
-
"uuid": "550e8400-e29b-41d4-a716-446655440001",
|
631
|
-
"server": {"host": "0.0.0.0", "port": 8443},
|
632
|
-
"protocols": {"enabled": True, "allowed_protocols": ["https"]},
|
633
|
-
"ssl": {
|
634
|
-
"enabled": True,
|
635
|
-
"cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_cert.pem",
|
636
|
-
"key_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_key.pem",
|
637
|
-
"ca_cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/ca_cert.pem",
|
638
|
-
"verify_client": False,
|
639
|
-
"min_tls_version": "TLSv1.2",
|
640
|
-
},
|
641
|
-
"logging": {"level": "INFO"},
|
642
|
-
},
|
643
|
-
"mtls_with_roles.json": {
|
623
|
+
"comprehensive_http.json": {
|
644
624
|
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
645
|
-
"server": {
|
646
|
-
|
625
|
+
"server": {
|
626
|
+
"host": "127.0.0.1",
|
627
|
+
"port": 20001,
|
628
|
+
"debug": False,
|
629
|
+
"log_level": "INFO",
|
630
|
+
"workers": 1,
|
631
|
+
"reload": False
|
632
|
+
},
|
647
633
|
"ssl": {
|
648
|
-
"enabled":
|
649
|
-
"cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_cert.pem",
|
650
|
-
"key_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_key.pem",
|
651
|
-
"ca_cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/ca_cert.pem",
|
652
|
-
"verify_client": True,
|
653
|
-
"min_tls_version": "TLSv1.2",
|
634
|
+
"enabled": False
|
654
635
|
},
|
655
636
|
"security": {
|
637
|
+
"enabled": True,
|
656
638
|
"auth": {
|
657
639
|
"enabled": True,
|
658
|
-
"
|
659
|
-
|
640
|
+
"methods": [
|
641
|
+
"api_key"
|
642
|
+
],
|
643
|
+
"api_keys": {
|
644
|
+
"admin-token-123": "admin",
|
645
|
+
"user-token-456": "user",
|
646
|
+
"readonly-token-789": "readonly",
|
647
|
+
"guest-token-abc": "guest",
|
648
|
+
"proxy-token-def": "proxy"
|
649
|
+
}
|
660
650
|
},
|
661
|
-
|
662
|
-
"logging": {"level": "INFO"},
|
663
|
-
},
|
664
|
-
"mtls_no_roles.json": {
|
665
|
-
"server": {"host": "0.0.0.0", "port": 8443},
|
666
|
-
"protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]},
|
667
|
-
"security": {
|
668
|
-
"ssl": {
|
651
|
+
"permissions": {
|
669
652
|
"enabled": True,
|
670
|
-
"
|
671
|
-
"server_key_file": "keys/server_key.pem",
|
672
|
-
"ca_cert_file": "certs/ca_cert.pem",
|
673
|
-
"client_cert_file": "certs/client_cert.pem",
|
674
|
-
"client_key_file": "keys/client_key.pem",
|
675
|
-
"verify_server": True,
|
676
|
-
"verify_client": True,
|
677
|
-
"min_tls_version": "TLSv1.2",
|
653
|
+
"roles_file": "configs/roles.json"
|
678
654
|
}
|
679
655
|
},
|
680
|
-
"
|
681
|
-
},
|
682
|
-
"https_simple.json": {
|
683
|
-
"uuid": "550e8400-e29b-41d4-a716-446655440002",
|
684
|
-
"server": {"host": "0.0.0.0", "port": 8443},
|
685
|
-
"protocols": {"enabled": True, "allowed_protocols": ["https"]},
|
686
|
-
"ssl": {
|
656
|
+
"registration": {
|
687
657
|
"enabled": True,
|
688
|
-
"
|
689
|
-
"
|
690
|
-
"
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
"
|
700
|
-
"enabled": True,
|
701
|
-
"server_cert_file": "certs/server_cert.pem",
|
702
|
-
"server_key_file": "keys/server_key.pem",
|
703
|
-
"verify_server": True,
|
704
|
-
"ca_cert_file": "certs/ca_cert.pem",
|
705
|
-
"verify_client": False,
|
706
|
-
"min_tls_version": "TLSv1.2",
|
707
|
-
},
|
708
|
-
"auth": {
|
709
|
-
"enabled": True,
|
710
|
-
"token_required": True,
|
711
|
-
"token_secret": "your-secret-key",
|
712
|
-
},
|
713
|
-
},
|
714
|
-
"logging": {"level": "INFO"},
|
715
|
-
},
|
716
|
-
"test_proxy_registration.json": {
|
717
|
-
"server": {"host": "127.0.0.1", "port": 8010},
|
718
|
-
"protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]},
|
719
|
-
"security": {
|
720
|
-
"ssl": {
|
658
|
+
"url": "http://127.0.0.1:3004/proxy",
|
659
|
+
"name": "comprehensive_http_adapter",
|
660
|
+
"capabilities": [
|
661
|
+
"http",
|
662
|
+
"token_auth",
|
663
|
+
"roles",
|
664
|
+
"registration",
|
665
|
+
"heartbeat"
|
666
|
+
],
|
667
|
+
"retry_count": 3,
|
668
|
+
"retry_delay": 5,
|
669
|
+
"heartbeat": {
|
721
670
|
"enabled": True,
|
722
|
-
"
|
723
|
-
"server_key_file": "certs/mtls/server/embedding-service.key",
|
724
|
-
"ca_cert_file": "certs/mtls/truststore.pem",
|
725
|
-
"client_cert_file": "certs/mtls/client/embedding-service.pem",
|
726
|
-
"client_key_file": "certs/mtls/client/embedding-service.key",
|
727
|
-
"verify_server": True,
|
728
|
-
"verify_client": True,
|
729
|
-
"min_tls_version": "TLSv1.2",
|
671
|
+
"interval": 30
|
730
672
|
}
|
731
673
|
},
|
732
|
-
"
|
674
|
+
"protocols": {
|
733
675
|
"enabled": True,
|
734
|
-
"
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
"certificate": {
|
740
|
-
"cert_file": "certs/mtls/client/embedding-service.pem",
|
741
|
-
"key_file": "certs/mtls/client/embedding-service.key",
|
742
|
-
},
|
743
|
-
"ssl": {
|
744
|
-
"verify_mode": "CERT_REQUIRED",
|
745
|
-
"ca_cert": "mtls_certificates/truststore.pem",
|
746
|
-
},
|
747
|
-
},
|
748
|
-
"logging": {"level": "DEBUG"},
|
749
|
-
},
|
676
|
+
"allowed_protocols": [
|
677
|
+
"http"
|
678
|
+
]
|
679
|
+
}
|
680
|
+
}
|
750
681
|
}
|
751
682
|
|
752
683
|
# Generate and validate configurations
|
@@ -777,41 +708,81 @@ def generate_enhanced_configurations(output_dir: Path) -> None:
|
|
777
708
|
index_path = configs_dir / "README.md"
|
778
709
|
with open(index_path, "w", encoding="utf-8") as f:
|
779
710
|
f.write(
|
780
|
-
"""# Configuration
|
711
|
+
"""# Comprehensive HTTP Configuration
|
712
|
+
|
713
|
+
This directory contains a single comprehensive HTTP configuration with all features enabled.
|
714
|
+
|
715
|
+
## Available Configuration
|
781
716
|
|
782
|
-
|
717
|
+
### Comprehensive HTTP
|
718
|
+
- `comprehensive_http.json` - Complete HTTP server with all features
|
783
719
|
|
784
|
-
##
|
720
|
+
## Features
|
785
721
|
|
786
|
-
###
|
787
|
-
-
|
722
|
+
### Security
|
723
|
+
- **Token Authentication**: API key-based access control with 5 predefined tokens
|
724
|
+
- **Role-based Permissions**: Granular access control with 5 roles
|
725
|
+
- **Roles**: admin, user, readonly, guest, proxy
|
788
726
|
|
789
|
-
###
|
790
|
-
- `
|
791
|
-
- `
|
792
|
-
- `
|
727
|
+
### Authentication Tokens
|
728
|
+
- `admin-token-123` → admin role (full access)
|
729
|
+
- `user-token-456` → user role (read, write, execute)
|
730
|
+
- `readonly-token-789` → readonly role (read only)
|
731
|
+
- `guest-token-abc` → guest role (limited access)
|
732
|
+
- `proxy-token-def` → proxy role (registration, heartbeat)
|
793
733
|
|
794
|
-
###
|
795
|
-
-
|
796
|
-
-
|
734
|
+
### Registration & Monitoring
|
735
|
+
- **Proxy Registration**: Automatic service discovery
|
736
|
+
- **Heartbeat**: 30-second health monitoring
|
737
|
+
- **Retry Logic**: 3 attempts with 5-second delay
|
738
|
+
|
739
|
+
### Protocols
|
740
|
+
- **HTTP**: Standard web protocol (port 20001)
|
797
741
|
|
798
742
|
## Usage
|
799
743
|
|
800
|
-
|
744
|
+
### Starting the Server
|
745
|
+
```bash
|
746
|
+
# Start comprehensive HTTP server
|
747
|
+
python -m mcp_proxy_adapter --config configs/comprehensive_http.json
|
748
|
+
```
|
801
749
|
|
750
|
+
### Testing Authentication
|
802
751
|
```bash
|
803
|
-
|
752
|
+
# Test with admin token
|
753
|
+
curl -H "Authorization: Bearer admin-token-123" http://localhost:20001/health
|
754
|
+
|
755
|
+
# Test with user token
|
756
|
+
curl -H "Authorization: Bearer user-token-456" http://localhost:20001/health
|
757
|
+
|
758
|
+
# Test with readonly token
|
759
|
+
curl -H "Authorization: Bearer readonly-token-789" http://localhost:20001/health
|
804
760
|
```
|
805
761
|
|
806
|
-
##
|
762
|
+
## Configuration Details
|
807
763
|
|
808
|
-
|
809
|
-
-
|
810
|
-
-
|
811
|
-
-
|
812
|
-
-
|
764
|
+
- **Server**: 127.0.0.1:20001
|
765
|
+
- **SSL**: Disabled (HTTP only)
|
766
|
+
- **Authentication**: Token-based with roles
|
767
|
+
- **Registration**: Enabled with proxy server
|
768
|
+
- **Heartbeat**: 30-second interval
|
769
|
+
- **Protocols**: HTTP only
|
770
|
+
|
771
|
+
## Customization
|
772
|
+
|
773
|
+
Edit `comprehensive_http.json` to:
|
774
|
+
- Change server host/port
|
775
|
+
- Add/modify authentication tokens
|
776
|
+
- Update role permissions
|
777
|
+
- Modify registration settings
|
778
|
+
- Adjust heartbeat interval
|
779
|
+
|
780
|
+
## Troubleshooting
|
813
781
|
|
814
|
-
|
782
|
+
1. **Port Conflicts**: Ensure port 20001 is not in use
|
783
|
+
2. **Token Issues**: Verify token format and role mapping
|
784
|
+
3. **Registration Issues**: Check proxy server availability
|
785
|
+
4. **Permission Errors**: Verify roles.json file exists
|
815
786
|
"""
|
816
787
|
)
|
817
788
|
|
mcp_proxy_adapter/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-proxy-adapter
|
3
|
-
Version: 6.
|
3
|
+
Version: 6.4.1
|
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=idp3KUR7CT7kTXLVPvvclJlNnt8d_HYl8_jY98uknmo,4677
|
6
6
|
mcp_proxy_adapter/openapi.py,sha256=2UZOI09ZDRJuBYBjKbMyb2U4uASszoCMD5o_4ktRpvg,13480
|
7
|
-
mcp_proxy_adapter/version.py,sha256=
|
7
|
+
mcp_proxy_adapter/version.py,sha256=P9qw3X3vfbgoqSgoCae8MiE-WtXOwkrl5G370CizL5E,75
|
8
8
|
mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
mcp_proxy_adapter/api/app.py,sha256=dIsAWbQFWMa8zxhPro9hxUnUuqnLWlqutWAKrqJIHGE,33386
|
10
10
|
mcp_proxy_adapter/api/handlers.py,sha256=iyFGoEuUS1wxbV1ELA0zmaxIyQR7j4zw-4MrD-uIO6E,8294
|
@@ -20,8 +20,8 @@ mcp_proxy_adapter/api/middleware/logging.py,sha256=iME87hrbvyTjI-RJro5Cwao7VlHUI
|
|
20
20
|
mcp_proxy_adapter/api/middleware/performance.py,sha256=-EvA7YIcTlxn8RuxlWlScJvX2EIoeEp3P5dKVWZHYRY,2357
|
21
21
|
mcp_proxy_adapter/api/middleware/protocol_middleware.py,sha256=YiwgeWXaFjj-TvTpAyqOMu1Rql4UENmX6pAJ8vEb9T8,15449
|
22
22
|
mcp_proxy_adapter/api/middleware/transport_middleware.py,sha256=VG1rWyuh-O2pdc0kQ3SADFvyh286o5Wrnkt8OFQ0WQw,4274
|
23
|
-
mcp_proxy_adapter/api/middleware/unified_security.py,sha256=
|
24
|
-
mcp_proxy_adapter/api/middleware/user_info_middleware.py,sha256=
|
23
|
+
mcp_proxy_adapter/api/middleware/unified_security.py,sha256=qjNPOCusMimXjEtjwyG6CgFieLm2T7O2e2QghqE_s3M,8313
|
24
|
+
mcp_proxy_adapter/api/middleware/user_info_middleware.py,sha256=sUHHyy33xvZKRDtOWfzbndrIxDYLUFeVYfUbPIKawR8,10652
|
25
25
|
mcp_proxy_adapter/commands/__init__.py,sha256=eStfu2UrLfMvMTY6x20GD8sMPmPB1so-0QZQYV53nqo,1565
|
26
26
|
mcp_proxy_adapter/commands/auth_validation_command.py,sha256=p4UrAaHyoCxMy98G1BUUlFJWjoelEJzX3OAWIiQaGls,14593
|
27
27
|
mcp_proxy_adapter/commands/base.py,sha256=0_hu8t89-2vWBPFpEMokr27A-IifKI32rkQwZfc2Grk,15162
|
@@ -32,7 +32,7 @@ mcp_proxy_adapter/commands/certificate_management_command.py,sha256=TDoGV2mnEz1H
|
|
32
32
|
mcp_proxy_adapter/commands/command_registry.py,sha256=RFGZw-0A29P6ZQMZ2qi5wQe3K89hCNOqRTdhtYYDGDg,36498
|
33
33
|
mcp_proxy_adapter/commands/config_command.py,sha256=PWX1OhKAmjlc8CSy4-sImdvGeSNgDNyv30Y-P5iZp9g,3767
|
34
34
|
mcp_proxy_adapter/commands/dependency_container.py,sha256=mvPob62lQ-mKRbAA9aL3L5gOT9_4V2Vy2cGoup2S840,3239
|
35
|
-
mcp_proxy_adapter/commands/dependency_manager.py,sha256=
|
35
|
+
mcp_proxy_adapter/commands/dependency_manager.py,sha256=lXgtrhCiQhy9Y-QpU_RWRg2d0VYy5msoNQPUjPOcOc8,8245
|
36
36
|
mcp_proxy_adapter/commands/echo_command.py,sha256=7E4DGGYULt6XN7NOTHwpmM9rMJgJ-ykMTqImOXY8160,2378
|
37
37
|
mcp_proxy_adapter/commands/health_command.py,sha256=Li0snwkFHdeYdYy4Nrrt_OpLU9cZedfoNatndT_yLUo,4543
|
38
38
|
mcp_proxy_adapter/commands/help_command.py,sha256=y6-li7XLAS_W4forLO-8r4QsnKVqzB2OmQzNKcMZ1f8,14224
|
@@ -89,7 +89,8 @@ mcp_proxy_adapter/examples/demo_client.py,sha256=en2Rtb70B1sQmhL-vdQ4PDpKNNl_mfl
|
|
89
89
|
mcp_proxy_adapter/examples/generate_all_certificates.py,sha256=lLP5RKmJwpSyprvrxQXFt_xcN4aiUzlIxk5WVdXx2Fk,19024
|
90
90
|
mcp_proxy_adapter/examples/generate_certificates.py,sha256=VRJnT9Za2Wk_oKRT5g2SA7qcGeBSxZm9wPMOM5i50T0,6707
|
91
91
|
mcp_proxy_adapter/examples/generate_certificates_and_tokens.py,sha256=hUCoJH3fy5WeR_YMHj-_W0mR0ZKUWqewH4FVN3yWyrM,17972
|
92
|
-
mcp_proxy_adapter/examples/
|
92
|
+
mcp_proxy_adapter/examples/generate_comprehensive_config.py,sha256=2UyTGIUKxw3EdCFaOMwO1vB-OZjOQV0senU44JPuyH0,4787
|
93
|
+
mcp_proxy_adapter/examples/generate_test_configs.py,sha256=RorZOrhjtoFwtC0Y0kQK7wBA1OnvHDod9nK-C2PMgPo,14323
|
93
94
|
mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=vemRhftnjbiOBCJkmtDGqlWQ8syTG0a8755GCOnaQsg,12503
|
94
95
|
mcp_proxy_adapter/examples/run_example.py,sha256=yp-a6HIrSk3ddQmbn0KkuKwErId0aNfj028TE6U-zmY,2626
|
95
96
|
mcp_proxy_adapter/examples/run_full_test_suite.py,sha256=bR25OOrmWnLQccZno9cZhi_Ltk_6k8DFR2vXPCj1XQ4,12468
|
@@ -97,14 +98,14 @@ mcp_proxy_adapter/examples/run_proxy_server.py,sha256=SBLSSY2F_VEBQD3MsCE_Pa9xFE
|
|
97
98
|
mcp_proxy_adapter/examples/run_security_tests.py,sha256=0vjaUdWC-rLyviQuNxM3PtfiU9TzSRuxGxWMehrFA_w,23311
|
98
99
|
mcp_proxy_adapter/examples/run_security_tests_fixed.py,sha256=2BKMT0_-FhmcZA73hdQOt2XR7Cgb9Sq8qBI88BkwAAA,10934
|
99
100
|
mcp_proxy_adapter/examples/security_test_client.py,sha256=K5gEVat1SJS2pBVxqLl5c9-uiiG12k8UT3ULQDXZ2Uc,35713
|
100
|
-
mcp_proxy_adapter/examples/setup_test_environment.py,sha256=
|
101
|
-
mcp_proxy_adapter/examples/setup_test_environment_old.py,sha256=qV7IT8lMObcaPeNrFXI7CkuvJnbJsLIVaRn7fTFXjJ0,11631
|
101
|
+
mcp_proxy_adapter/examples/setup_test_environment.py,sha256=LR4kGneHELgk4lHMfA9k1yFZ1o3KEQelqOXua5oT88Q,34540
|
102
102
|
mcp_proxy_adapter/examples/test_config.py,sha256=ekEoUZe9q484vU_0IxOVhQdNMVJXG3IpmQpP--VmuDI,6491
|
103
103
|
mcp_proxy_adapter/examples/test_config_generator.py,sha256=PBXk1V_awJ-iBlbE66Pme5sQwu6CJDxkmqgm8uPtM58,4091
|
104
104
|
mcp_proxy_adapter/examples/test_examples.py,sha256=CYlVatdHUVC_rwv4NsvxFG3GXiKIyxPDUH43BOJHjrU,12330
|
105
105
|
mcp_proxy_adapter/examples/universal_client.py,sha256=n1-cBPOiCipA86Zcc_mI_jMywDMZS1p3u5JT3AqTsrQ,27577
|
106
106
|
mcp_proxy_adapter/examples/basic_framework/__init__.py,sha256=4aYD--R6hy9n9CUxj7Osb9HcdVUMJ6_cfpu4ujkbCwI,345
|
107
107
|
mcp_proxy_adapter/examples/basic_framework/main.py,sha256=AkGUXW05_AK8SEKwlS_0isJKKqjulKBDPp7t36t9QJk,1787
|
108
|
+
mcp_proxy_adapter/examples/basic_framework/roles.json,sha256=I0lSP3hfq1DESv3xsZ7-xOEdzaQGCb8b9YMK_AOPDsE,510
|
108
109
|
mcp_proxy_adapter/examples/basic_framework/commands/__init__.py,sha256=_VQNLUEdsxUG-4yt9BZI_vtOxHAdGG0OUSsP6Wj-Vz4,76
|
109
110
|
mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py,sha256=IE_EIXMnkdXuakZn7wLD9kBFyfDF5lYi56ejgiBeb-A,70
|
110
111
|
mcp_proxy_adapter/examples/commands/__init__.py,sha256=zvY_OpH_B1bVc_khrNIl6O8vqCw1FH6gGMAsJAkGWGY,170
|
@@ -124,6 +125,7 @@ mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks
|
|
124
125
|
mcp_proxy_adapter/examples/full_application/__init__.py,sha256=xGiPYhRAzs1Fh9wA8HoowV-Gg9QMLaMZn-OamExq1TI,320
|
125
126
|
mcp_proxy_adapter/examples/full_application/main.py,sha256=ogL3Bil_5puGnwvMh3YNOjrW76FIzzoggKEp-04HSfo,7855
|
126
127
|
mcp_proxy_adapter/examples/full_application/proxy_endpoints.py,sha256=Kt_WAsG61HLTMkKQ1mQqjvlX9I4TcfwYq0NaRR9HKvM,6179
|
128
|
+
mcp_proxy_adapter/examples/full_application/roles.json,sha256=I0lSP3hfq1DESv3xsZ7-xOEdzaQGCb8b9YMK_AOPDsE,510
|
127
129
|
mcp_proxy_adapter/examples/full_application/commands/__init__.py,sha256=yQHxVSFkAyFLUOdk42QOebUODPlQV9IbydPgF3UKsGM,217
|
128
130
|
mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py,sha256=H7FPJmVJNWT61rPWxep06-7hsYRt8XYBUSBiwqpBurU,3096
|
129
131
|
mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py,sha256=DFTqVnIDt6nBdZ27-vD_f1X2cFcDInVQiCEq9ltw4lA,3428
|
@@ -137,8 +139,8 @@ mcp_proxy_adapter/schemas/base_schema.json,sha256=v9G9cGMd4dRhCZsOQ_FMqOi5VFyVbI
|
|
137
139
|
mcp_proxy_adapter/schemas/openapi_schema.json,sha256=C3yLkwmDsvnLW9B5gnKKdBGl4zxkeU-rEmjTrNVsQU0,8405
|
138
140
|
mcp_proxy_adapter/utils/config_generator.py,sha256=UXxuxxAyKTesAS3DOofQ26e20v771inA7EfBV8PZD1c,47543
|
139
141
|
mcp_proxy_adapter_issue_package/demonstrate_issue.py,sha256=O54fwWQvUAjEGiHhQGm1JLnARkhVCwAqjBk_89HyRbY,7894
|
140
|
-
mcp_proxy_adapter-6.
|
141
|
-
mcp_proxy_adapter-6.
|
142
|
-
mcp_proxy_adapter-6.
|
143
|
-
mcp_proxy_adapter-6.
|
144
|
-
mcp_proxy_adapter-6.
|
142
|
+
mcp_proxy_adapter-6.4.1.dist-info/METADATA,sha256=z0V7ZTjQlTXg1cGCGu5NaRbvqQk4Z7moSp3lvLeNgKE,22403
|
143
|
+
mcp_proxy_adapter-6.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
144
|
+
mcp_proxy_adapter-6.4.1.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
|
145
|
+
mcp_proxy_adapter-6.4.1.dist-info/top_level.txt,sha256=CHk-Mc-AxjO-tRheegA2qLiQnU4vZRnxuTF81So6SAc,50
|
146
|
+
mcp_proxy_adapter-6.4.1.dist-info/RECORD,,
|
@@ -1,316 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Author: Vasiliy Zdanovskiy
|
4
|
-
email: vasilyvz@gmail.com
|
5
|
-
Script for setting up test environment for MCP Proxy Adapter.
|
6
|
-
Prepares the test environment with all necessary files and directories.
|
7
|
-
Uses mcp_security_framework for certificate generation.
|
8
|
-
|
9
|
-
This script accepts an output directory and copies required example files
|
10
|
-
and helper scripts into that directory, creating a ready-to-use workspace.
|
11
|
-
By default, the current working directory is used, so end-users can run
|
12
|
-
it in their project root after installing this framework in a virtual
|
13
|
-
environment.
|
14
|
-
"""
|
15
|
-
import shutil
|
16
|
-
import sys
|
17
|
-
import argparse
|
18
|
-
from pathlib import Path
|
19
|
-
|
20
|
-
# Import mcp_security_framework
|
21
|
-
try:
|
22
|
-
from mcp_security_framework.core.cert_manager import CertificateManager
|
23
|
-
from mcp_security_framework.schemas.config import (
|
24
|
-
CertificateConfig,
|
25
|
-
CAConfig,
|
26
|
-
ServerCertConfig,
|
27
|
-
ClientCertConfig,
|
28
|
-
)
|
29
|
-
|
30
|
-
SECURITY_FRAMEWORK_AVAILABLE = True
|
31
|
-
except ImportError:
|
32
|
-
SECURITY_FRAMEWORK_AVAILABLE = False
|
33
|
-
print("Warning: mcp_security_framework not available")
|
34
|
-
|
35
|
-
|
36
|
-
def _get_package_paths() -> tuple[Path, Path]:
|
37
|
-
"""
|
38
|
-
Resolve source paths for examples and utils relative to this file
|
39
|
-
to avoid importing the package during setup.
|
40
|
-
"""
|
41
|
-
pkg_root = Path(__file__).resolve().parents[1]
|
42
|
-
return pkg_root / "examples", pkg_root / "utils"
|
43
|
-
|
44
|
-
|
45
|
-
def setup_test_environment(output_dir: Path) -> None:
|
46
|
-
"""
|
47
|
-
Setup test environment under output_dir with required files
|
48
|
-
and directories.
|
49
|
-
|
50
|
-
All created directories and copied files are rooted at output_dir
|
51
|
-
so users can run scripts relative to that directory.
|
52
|
-
"""
|
53
|
-
print("🔧 Setting up test environment...")
|
54
|
-
output_dir = output_dir.resolve()
|
55
|
-
output_dir.mkdir(parents=True, exist_ok=True)
|
56
|
-
# Create test environment directory structure
|
57
|
-
directories = [
|
58
|
-
"examples/basic_framework",
|
59
|
-
"examples/full_application",
|
60
|
-
"scripts",
|
61
|
-
"configs",
|
62
|
-
"certs",
|
63
|
-
"keys",
|
64
|
-
"tokens",
|
65
|
-
"logs",
|
66
|
-
]
|
67
|
-
for directory in directories:
|
68
|
-
target_dir = output_dir / directory
|
69
|
-
target_dir.mkdir(parents=True, exist_ok=True)
|
70
|
-
print(f"✅ Created directory: {target_dir}")
|
71
|
-
# Resolve package paths
|
72
|
-
examples_src_root, utils_src_root = _get_package_paths()
|
73
|
-
# Copy example files
|
74
|
-
basic_framework_src = examples_src_root / "basic_framework"
|
75
|
-
if basic_framework_src.exists():
|
76
|
-
shutil.copytree(
|
77
|
-
basic_framework_src,
|
78
|
-
output_dir / "examples/basic_framework",
|
79
|
-
dirs_exist_ok=True,
|
80
|
-
)
|
81
|
-
print("✅ Copied basic_framework examples")
|
82
|
-
full_application_src = examples_src_root / "full_application"
|
83
|
-
if full_application_src.exists():
|
84
|
-
shutil.copytree(
|
85
|
-
full_application_src,
|
86
|
-
output_dir / "examples/full_application",
|
87
|
-
dirs_exist_ok=True,
|
88
|
-
)
|
89
|
-
print("✅ Copied full_application examples")
|
90
|
-
# Copy utility scripts
|
91
|
-
config_generator_src = utils_src_root / "config_generator.py"
|
92
|
-
if config_generator_src.exists():
|
93
|
-
shutil.copy2(config_generator_src, output_dir / "scripts/")
|
94
|
-
print("✅ Copied config_generator.py")
|
95
|
-
# Copy certificate generation scripts
|
96
|
-
create_certs_src = examples_src_root / "create_certificates_simple.py"
|
97
|
-
if create_certs_src.exists():
|
98
|
-
shutil.copy2(create_certs_src, output_dir / "scripts/")
|
99
|
-
print("✅ Copied create_certificates_simple.py")
|
100
|
-
cert_tokens_src = examples_src_root / "generate_certificates_and_tokens.py"
|
101
|
-
if cert_tokens_src.exists():
|
102
|
-
shutil.copy2(cert_tokens_src, output_dir / "scripts/")
|
103
|
-
print("✅ Copied generate_certificates_and_tokens.py")
|
104
|
-
|
105
|
-
# Copy roles.json to the root directory for compatibility
|
106
|
-
roles_src = examples_src_root / "roles.json"
|
107
|
-
if roles_src.exists():
|
108
|
-
shutil.copy2(roles_src, output_dir)
|
109
|
-
print("✅ Copied roles.json to root directory")
|
110
|
-
|
111
|
-
# Also copy from configs directory if it exists
|
112
|
-
roles_configs_src = output_dir / "configs" / "roles.json"
|
113
|
-
if roles_configs_src.exists():
|
114
|
-
shutil.copy2(roles_configs_src, output_dir / "roles.json")
|
115
|
-
print("✅ Updated roles.json from configs directory")
|
116
|
-
print("🎉 Test environment setup completed successfully at: {}".format(output_dir))
|
117
|
-
|
118
|
-
|
119
|
-
def generate_certificates_with_framework(output_dir: Path) -> bool:
|
120
|
-
"""
|
121
|
-
Generate certificates using mcp_security_framework.
|
122
|
-
"""
|
123
|
-
if not SECURITY_FRAMEWORK_AVAILABLE:
|
124
|
-
print("❌ mcp_security_framework not available for certificate " "generation")
|
125
|
-
return False
|
126
|
-
try:
|
127
|
-
print("🔐 Generating certificates using mcp_security_framework...")
|
128
|
-
# Configure certificate manager
|
129
|
-
cert_config = CertificateConfig(
|
130
|
-
cert_storage_path=str((output_dir / "certs").resolve()),
|
131
|
-
key_storage_path=str((output_dir / "keys").resolve()),
|
132
|
-
default_validity_days=365,
|
133
|
-
key_size=2048,
|
134
|
-
hash_algorithm="sha256",
|
135
|
-
)
|
136
|
-
cert_manager = CertificateManager(cert_config)
|
137
|
-
# Generate CA certificate
|
138
|
-
ca_config = CAConfig(
|
139
|
-
common_name="MCP Proxy Adapter Test CA",
|
140
|
-
organization="Test Organization",
|
141
|
-
organizational_unit="Certificate Authority",
|
142
|
-
country="US",
|
143
|
-
state="Test State",
|
144
|
-
locality="Test City",
|
145
|
-
validity_years=10, # Use validity_years instead of validity_days
|
146
|
-
key_size=2048,
|
147
|
-
hash_algorithm="sha256",
|
148
|
-
)
|
149
|
-
cert_pair = cert_manager.create_root_ca(ca_config)
|
150
|
-
if not cert_pair or not cert_pair.certificate_path:
|
151
|
-
print("❌ Failed to create CA certificate: Invalid certificate pair")
|
152
|
-
return False
|
153
|
-
print("✅ CA certificate created successfully")
|
154
|
-
# Find CA key file
|
155
|
-
ca_key_path = cert_pair.private_key_path
|
156
|
-
# Generate server certificate
|
157
|
-
server_config = ServerCertConfig(
|
158
|
-
common_name="localhost",
|
159
|
-
organization="Test Organization",
|
160
|
-
organizational_unit="Server",
|
161
|
-
country="US",
|
162
|
-
state="Test State",
|
163
|
-
locality="Test City",
|
164
|
-
validity_days=365,
|
165
|
-
key_size=2048,
|
166
|
-
hash_algorithm="sha256",
|
167
|
-
subject_alt_names=[
|
168
|
-
"localhost",
|
169
|
-
"127.0.0.1",
|
170
|
-
],
|
171
|
-
ca_cert_path=cert_pair.certificate_path,
|
172
|
-
ca_key_path=ca_key_path,
|
173
|
-
)
|
174
|
-
cert_pair = cert_manager.create_server_certificate(server_config)
|
175
|
-
if not cert_pair or not cert_pair.certificate_path:
|
176
|
-
print("❌ Failed to create server certificate: Invalid certificate " "pair")
|
177
|
-
return False
|
178
|
-
print("✅ Server certificate created successfully")
|
179
|
-
# Generate client certificates
|
180
|
-
client_configs = [
|
181
|
-
(
|
182
|
-
"admin",
|
183
|
-
["admin"],
|
184
|
-
[
|
185
|
-
"read",
|
186
|
-
"write",
|
187
|
-
"execute",
|
188
|
-
"delete",
|
189
|
-
"admin",
|
190
|
-
"register",
|
191
|
-
"unregister",
|
192
|
-
"heartbeat",
|
193
|
-
"discover",
|
194
|
-
],
|
195
|
-
),
|
196
|
-
(
|
197
|
-
"user",
|
198
|
-
["user"],
|
199
|
-
[
|
200
|
-
"read",
|
201
|
-
"execute",
|
202
|
-
"register",
|
203
|
-
"unregister",
|
204
|
-
"heartbeat",
|
205
|
-
"discover",
|
206
|
-
],
|
207
|
-
),
|
208
|
-
("readonly", ["readonly"], ["read", "discover"]),
|
209
|
-
("guest", ["guest"], ["read", "discover"]),
|
210
|
-
(
|
211
|
-
"proxy",
|
212
|
-
["proxy"],
|
213
|
-
["register", "unregister", "heartbeat", "discover"],
|
214
|
-
),
|
215
|
-
]
|
216
|
-
for client_name, roles, permissions in client_configs:
|
217
|
-
client_config = ClientCertConfig(
|
218
|
-
common_name=f"{client_name}-client",
|
219
|
-
organization="Test Organization",
|
220
|
-
organizational_unit="Client",
|
221
|
-
country="US",
|
222
|
-
state="Test State",
|
223
|
-
locality="Test City",
|
224
|
-
validity_days=730,
|
225
|
-
key_size=2048,
|
226
|
-
hash_algorithm="sha256",
|
227
|
-
roles=roles,
|
228
|
-
permissions=permissions,
|
229
|
-
ca_cert_path=cert_pair.certificate_path,
|
230
|
-
ca_key_path=ca_key_path,
|
231
|
-
)
|
232
|
-
cert_pair = cert_manager.create_client_certificate(client_config)
|
233
|
-
if not cert_pair or not cert_pair.certificate_path:
|
234
|
-
print(
|
235
|
-
(
|
236
|
-
"❌ Failed to create client certificate {}: "
|
237
|
-
"Invalid certificate pair"
|
238
|
-
).format(client_name)
|
239
|
-
)
|
240
|
-
return False
|
241
|
-
print("✅ Client certificate {} created successfully".format(client_name))
|
242
|
-
print(
|
243
|
-
"🎉 All certificates generated successfully using "
|
244
|
-
"mcp_security_framework!"
|
245
|
-
)
|
246
|
-
return True
|
247
|
-
except Exception as e:
|
248
|
-
print("❌ Error generating certificates with framework: {}".format(e))
|
249
|
-
print("\n🔧 TROUBLESHOOTING:")
|
250
|
-
print("1. Check if mcp_security_framework is installed:")
|
251
|
-
print(" pip install mcp_security_framework")
|
252
|
-
print("\n2. Verify write permissions in output directory")
|
253
|
-
print("\n3. Check if certs/ and keys/ directories exist")
|
254
|
-
return False
|
255
|
-
|
256
|
-
|
257
|
-
def main() -> int:
|
258
|
-
"""Main function for command line execution."""
|
259
|
-
parser = argparse.ArgumentParser(
|
260
|
-
description="Setup test environment for MCP Proxy Adapter"
|
261
|
-
)
|
262
|
-
parser.add_argument(
|
263
|
-
"--output-dir",
|
264
|
-
"-o",
|
265
|
-
type=str,
|
266
|
-
default=".",
|
267
|
-
help=(
|
268
|
-
"Target directory to create the test environment "
|
269
|
-
"(default: current directory)"
|
270
|
-
),
|
271
|
-
)
|
272
|
-
args = parser.parse_args()
|
273
|
-
try:
|
274
|
-
target_root = Path(args.output_dir)
|
275
|
-
setup_test_environment(target_root)
|
276
|
-
# Generate certificates if framework is available
|
277
|
-
if SECURITY_FRAMEWORK_AVAILABLE:
|
278
|
-
generate_certificates_with_framework(target_root)
|
279
|
-
else:
|
280
|
-
print(
|
281
|
-
"⚠️ Skipping certificate generation (mcp_security_framework "
|
282
|
-
"not available)"
|
283
|
-
)
|
284
|
-
except Exception as e:
|
285
|
-
print(
|
286
|
-
"❌ Error setting up test environment: {}".format(e),
|
287
|
-
file=sys.stderr,
|
288
|
-
)
|
289
|
-
print("\n🔧 TROUBLESHOOTING:")
|
290
|
-
print("1. Check if output directory is writable")
|
291
|
-
print("2. Verify mcp_security_framework installation")
|
292
|
-
print("3. Check available disk space")
|
293
|
-
return 1
|
294
|
-
|
295
|
-
print("\n" + "=" * 60)
|
296
|
-
print("✅ TEST ENVIRONMENT SETUP COMPLETED SUCCESSFULLY")
|
297
|
-
print("=" * 60)
|
298
|
-
print("\n📋 NEXT STEPS:")
|
299
|
-
print("1. Generate test configurations:")
|
300
|
-
print(
|
301
|
-
" python -m mcp_proxy_adapter.examples.generate_test_configs --output-dir configs"
|
302
|
-
)
|
303
|
-
print("\n2. Generate additional certificates (if needed):")
|
304
|
-
print(" python -m mcp_proxy_adapter.examples.generate_certificates")
|
305
|
-
print("\n3. Run security tests:")
|
306
|
-
print(" python -m mcp_proxy_adapter.examples.run_security_tests")
|
307
|
-
print("\n4. Start basic framework example:")
|
308
|
-
print(
|
309
|
-
" python -m mcp_proxy_adapter.examples.basic_framework.main --config configs/https_simple.json"
|
310
|
-
)
|
311
|
-
print("=" * 60)
|
312
|
-
return 0
|
313
|
-
|
314
|
-
|
315
|
-
if __name__ == "__main__":
|
316
|
-
exit(main())
|
File without changes
|
File without changes
|
File without changes
|