mcp-proxy-adapter 6.2.18__py3-none-any.whl → 6.2.22__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.
@@ -16,7 +16,7 @@ from mcp_proxy_adapter.api.app import create_app
16
16
 
17
17
  def main():
18
18
  """Main CLI entry point."""
19
- print("MCP Proxy Adapter v6.2.18")
19
+ print("MCP Proxy Adapter v6.2.21")
20
20
  print("========================")
21
21
  print()
22
22
  print("Usage:")
@@ -350,6 +350,9 @@ def create_app(title: Optional[str] = None, description: Optional[str] = None, v
350
350
  )
351
351
 
352
352
  # Setup middleware using the new middleware package
353
+ print(f"DEBUG create_app: calling setup_middleware with config type: {type(current_config)}")
354
+ if hasattr(current_config, 'keys'):
355
+ print(f"DEBUG create_app: current_config keys: {list(current_config.keys())}")
353
356
  setup_middleware(app, current_config)
354
357
 
355
358
  # Use custom OpenAPI schema
@@ -23,18 +23,21 @@ def setup_middleware(app: FastAPI, app_config: Optional[Dict[str, Any]] = None)
23
23
  # Use provided configuration or fallback to global config
24
24
  current_config = app_config if app_config is not None else config.get_all()
25
25
 
26
+ # Add protocol middleware FIRST (before other middleware)
27
+ setup_protocol_middleware(app, current_config)
28
+
26
29
  # Create middleware factory
27
30
  factory = MiddlewareFactory(app, current_config)
28
-
31
+
29
32
  # Validate middleware configuration
30
33
  if not factory.validate_middleware_config():
31
34
  logger.error("Middleware configuration validation failed")
32
35
  raise SystemExit(1)
33
-
36
+
34
37
  logger.info("Using unified security middleware")
35
38
  middleware_list = factory.create_all_middleware()
36
-
37
- # Add middleware to application
39
+
40
+ # Add middleware to application AFTER protocol middleware
38
41
  for middleware in middleware_list:
39
42
  # For ASGI middleware, we need to wrap the application
40
43
  if hasattr(middleware, 'dispatch'):
@@ -43,9 +46,6 @@ def setup_middleware(app: FastAPI, app_config: Optional[Dict[str, Any]] = None)
43
46
  else:
44
47
  logger.warning(f"Middleware {middleware.__class__.__name__} doesn't have dispatch method")
45
48
 
46
- # Add protocol middleware with current configuration
47
- setup_protocol_middleware(app, current_config)
48
-
49
49
  # Log middleware information
50
50
  middleware_info = factory.get_middleware_info()
51
51
  logger.info(f"Middleware setup completed:")
@@ -24,15 +24,37 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
24
24
  def __init__(self, app, app_config: Optional[Dict[str, Any]] = None):
25
25
  """
26
26
  Initialize protocol middleware.
27
-
27
+
28
28
  Args:
29
29
  app: FastAPI application
30
30
  app_config: Application configuration dictionary (optional)
31
31
  """
32
32
  super().__init__(app)
33
- self.app_config = app_config
33
+ # Normalize config to dictionary
34
+ normalized_config: Optional[Dict[str, Any]]
35
+ if app_config is None:
36
+ normalized_config = None
37
+ elif hasattr(app_config, 'get_all'):
38
+ try:
39
+ normalized_config = app_config.get_all()
40
+ except Exception as e:
41
+ logger.debug(f"ProtocolMiddleware - Error calling get_all(): {e}, type: {type(app_config)}")
42
+ normalized_config = None
43
+ elif hasattr(app_config, 'keys'):
44
+ normalized_config = app_config # Already dict-like
45
+ else:
46
+ logger.debug(f"ProtocolMiddleware - app_config is not dict-like, type: {type(app_config)}, value: {repr(app_config)}")
47
+ normalized_config = None
48
+
49
+ logger.debug(f"ProtocolMiddleware - normalized_config type: {type(normalized_config)}")
50
+ if normalized_config:
51
+ logger.debug(f"ProtocolMiddleware - protocols in config: {'protocols' in normalized_config}")
52
+ if 'protocols' in normalized_config:
53
+ logger.debug(f"ProtocolMiddleware - protocols type: {type(normalized_config['protocols'])}")
54
+
55
+ self.app_config = normalized_config
34
56
  # Get protocol manager with current configuration
35
- self.protocol_manager = get_protocol_manager(app_config)
57
+ self.protocol_manager = get_protocol_manager(normalized_config)
36
58
 
37
59
  def update_config(self, new_config: Dict[str, Any]):
38
60
  """
@@ -41,21 +63,31 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
41
63
  Args:
42
64
  new_config: New configuration dictionary
43
65
  """
44
- self.app_config = new_config
45
- self.protocol_manager = get_protocol_manager(new_config)
66
+ # Normalize new config
67
+ if hasattr(new_config, 'get_all'):
68
+ try:
69
+ self.app_config = new_config.get_all()
70
+ except Exception:
71
+ self.app_config = None
72
+ elif hasattr(new_config, 'keys'):
73
+ self.app_config = new_config
74
+ else:
75
+ self.app_config = None
76
+ self.protocol_manager = get_protocol_manager(self.app_config)
46
77
  logger.info("Protocol middleware configuration updated")
47
78
 
48
79
  async def dispatch(self, request: Request, call_next: Callable) -> Response:
49
80
  """
50
81
  Process request through protocol middleware.
51
-
82
+
52
83
  Args:
53
84
  request: Incoming request
54
85
  call_next: Next middleware/endpoint function
55
-
86
+
56
87
  Returns:
57
88
  Response object
58
89
  """
90
+ logger.info(f"ProtocolMiddleware.dispatch called for {request.method} {request.url.path}")
59
91
  try:
60
92
  # Get protocol from request
61
93
  protocol = self._get_request_protocol(request)
@@ -132,22 +164,37 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
132
164
  def setup_protocol_middleware(app, app_config: Optional[Dict[str, Any]] = None):
133
165
  """
134
166
  Setup protocol middleware for FastAPI application.
135
-
167
+
136
168
  Args:
137
169
  app: FastAPI application
138
170
  app_config: Application configuration dictionary (optional)
139
171
  """
172
+ logger.info(f"setup_protocol_middleware - app_config type: {type(app_config)}")
173
+
140
174
  # Check if protocol management is enabled
141
175
  if app_config is None:
142
176
  from mcp_proxy_adapter.config import config
143
177
  app_config = config.get_all()
144
-
145
- protocols_config = app_config.get("protocols", {})
146
- enabled = protocols_config.get("enabled", True)
147
-
178
+ logger.info(f"setup_protocol_middleware - loaded from global config, type: {type(app_config)}")
179
+
180
+ logger.info(f"setup_protocol_middleware - final app_config type: {type(app_config)}")
181
+
182
+ if hasattr(app_config, 'get'):
183
+ logger.info(f"setup_protocol_middleware - app_config keys: {list(app_config.keys()) if hasattr(app_config, 'keys') else 'no keys'}")
184
+ protocols_config = app_config.get("protocols", {})
185
+ logger.info(f"setup_protocol_middleware - protocols_config type: {type(protocols_config)}")
186
+ enabled = protocols_config.get("enabled", True) if hasattr(protocols_config, 'get') else True
187
+ else:
188
+ logger.info(f"setup_protocol_middleware - app_config is not dict-like: {repr(app_config)}")
189
+ enabled = True
190
+
191
+ logger.info(f"setup_protocol_middleware - protocol management enabled: {enabled}")
192
+
148
193
  if enabled:
149
194
  # Create protocol middleware with current configuration
195
+ logger.info(f"setup_protocol_middleware - creating ProtocolMiddleware with config type: {type(app_config)}")
150
196
  middleware = ProtocolMiddleware(app, app_config)
197
+ logger.info(f"setup_protocol_middleware - adding middleware to app")
151
198
  app.add_middleware(ProtocolMiddleware, app_config=app_config)
152
199
  logger.info("Protocol middleware added to application")
153
200
  else:
@@ -61,19 +61,21 @@ class UnifiedSecurityMiddleware(BaseHTTPMiddleware):
61
61
  # Create security integration
62
62
  try:
63
63
  security_config = config.get("security", {})
64
- logger.info(f"DEBUG: Full config keys: {list(config.keys())}")
65
- logger.info(f"DEBUG: Security config: {security_config}")
66
- logger.info(f"DEBUG: Permissions in security: {'permissions' in security_config}")
67
64
  self.security_integration = create_security_integration(security_config)
68
65
  # Use framework's FastAPI middleware
69
66
  self.framework_middleware = self.security_integration.security_manager.create_fastapi_middleware()
70
67
  logger.info("Using mcp_security_framework FastAPI middleware")
68
+ # IMPORTANT: Don't replace self.app! This breaks the middleware chain.
69
+ # Instead, store the framework middleware for use in dispatch method.
70
+ logger.info("Framework middleware will be used in dispatch method")
71
71
  except Exception as e:
72
72
  logger.error(f"Security framework integration failed: {e}")
73
73
  # Instead of raising error, log warning and continue without security
74
74
  logger.warning("Continuing without security framework - some security features will be disabled")
75
75
  self.security_integration = None
76
76
  self.framework_middleware = None
77
+ # Keep original app in place when framework middleware is unavailable
78
+ # BaseHTTPMiddleware initialized it via super().__init__(app)
77
79
 
78
80
  logger.info("Unified security middleware initialized")
79
81
 
@@ -89,14 +91,45 @@ class UnifiedSecurityMiddleware(BaseHTTPMiddleware):
89
91
  Response object
90
92
  """
91
93
  try:
92
- # Use framework middleware if available
93
- if self.framework_middleware is not None:
94
- return await self.framework_middleware.dispatch(request, call_next)
94
+ # Simple built-in API key enforcement if configured
95
+ security_cfg = self.config.get("security", {}) if isinstance(self.config, dict) else {}
96
+ auth_cfg = security_cfg.get("auth", {})
97
+ permissions_cfg = security_cfg.get("permissions", {})
98
+ public_paths = set(auth_cfg.get("public_paths", ["/health", "/docs", "/openapi.json"]))
99
+ # JSON-RPC endpoint must not be public when API key is required
100
+ public_paths.discard("/api/jsonrpc")
101
+ path = request.url.path
102
+ methods = set(auth_cfg.get("methods", []))
103
+ api_keys: Dict[str, str] = auth_cfg.get("api_keys", {}) or {}
104
+
105
+ # Enforce only for non-public paths when api_key method configured
106
+ if security_cfg.get("enabled", False) and ("api_key" in methods) and (path not in public_paths):
107
+ # Accept either X-API-Key or Authorization: Bearer
108
+ token = request.headers.get("X-API-Key")
109
+ if not token:
110
+ authz = request.headers.get("Authorization", "")
111
+ if authz.startswith("Bearer "):
112
+ token = authz[7:]
113
+ if not token or (api_keys and token not in api_keys):
114
+ from fastapi.responses import JSONResponse
115
+ return JSONResponse(status_code=401, content={
116
+ "error": {
117
+ "code": 401,
118
+ "message": "Unauthorized: invalid or missing API key",
119
+ "type": "authentication_error"
120
+ }
121
+ })
122
+
123
+ # Continue with framework middleware or regular flow
124
+ if self.framework_middleware:
125
+ # If framework middleware exists, we need to call it manually
126
+ # This is a workaround since we can't chain ASGI apps in BaseHTTPMiddleware
127
+ logger.debug("Framework middleware exists, continuing with regular call_next")
128
+ return await call_next(request)
95
129
  else:
96
- # Fallback: continue without security middleware
97
- logger.debug("Security framework not available, continuing without security checks")
130
+ # No framework middleware, continue normally
98
131
  return await call_next(request)
99
-
132
+
100
133
  except SecurityValidationError as e:
101
134
  # Handle security validation errors
102
135
  return await self._handle_security_error(request, e)
@@ -15,6 +15,16 @@ from starlette.middleware.base import BaseHTTPMiddleware
15
15
 
16
16
  from mcp_proxy_adapter.core.logging import logger
17
17
 
18
+ # Import mcp_security_framework components
19
+ try:
20
+ from mcp_security_framework import AuthManager
21
+ from mcp_security_framework.schemas.config import AuthConfig
22
+ _MCP_SECURITY_AVAILABLE = True
23
+ print("✅ mcp_security_framework available in middleware")
24
+ except ImportError:
25
+ _MCP_SECURITY_AVAILABLE = False
26
+ print("⚠️ mcp_security_framework not available in middleware, using basic auth")
27
+
18
28
 
19
29
  class UserInfoMiddleware(BaseHTTPMiddleware):
20
30
  """
@@ -27,20 +37,43 @@ class UserInfoMiddleware(BaseHTTPMiddleware):
27
37
  def __init__(self, app, config: Dict[str, Any]):
28
38
  """
29
39
  Initialize user info middleware.
30
-
40
+
31
41
  Args:
32
42
  app: FastAPI application
33
43
  config: Configuration dictionary
34
44
  """
35
45
  super().__init__(app)
36
46
  self.config = config
37
-
38
- # Get API keys configuration
39
- security_config = config.get("security", {})
40
- auth_config = security_config.get("auth", {})
41
- self.api_keys = auth_config.get("api_keys", {})
42
-
43
- logger.info("User info middleware initialized")
47
+
48
+ # Initialize AuthManager if available
49
+ self.auth_manager = None
50
+ self._security_available = _MCP_SECURITY_AVAILABLE
51
+
52
+ if self._security_available:
53
+ try:
54
+ # Get API keys configuration
55
+ security_config = config.get("security", {})
56
+ auth_config = security_config.get("auth", {})
57
+
58
+ # Create AuthConfig for mcp_security_framework
59
+ mcp_auth_config = AuthConfig(
60
+ enabled=True,
61
+ methods=["api_key"],
62
+ api_keys=auth_config.get("api_keys", {})
63
+ )
64
+
65
+ self.auth_manager = AuthManager(mcp_auth_config)
66
+ logger.info("✅ User info middleware initialized with mcp_security_framework")
67
+ except Exception as e:
68
+ logger.warning(f"⚠️ Failed to initialize AuthManager: {e}")
69
+ self._security_available = False
70
+
71
+ if not self._security_available:
72
+ # Fallback to basic API key handling
73
+ security_config = config.get("security", {})
74
+ auth_config = security_config.get("auth", {})
75
+ self.api_keys = auth_config.get("api_keys", {})
76
+ logger.info("ℹ️ User info middleware initialized with basic auth")
44
77
 
45
78
  async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
46
79
  """
@@ -56,28 +89,70 @@ class UserInfoMiddleware(BaseHTTPMiddleware):
56
89
  # Extract API key from headers
57
90
  api_key = request.headers.get("X-API-Key")
58
91
 
59
- if api_key and api_key in self.api_keys:
60
- # Get user info from API key configuration
61
- user_config = self.api_keys[api_key]
62
-
63
- # Set user info in request.state
64
- request.state.user = {
65
- "id": api_key,
66
- "role": user_config.get("roles", ["guest"])[0] if user_config.get("roles") else "guest",
67
- "roles": user_config.get("roles", ["guest"]),
68
- "permissions": user_config.get("permissions", ["read"])
69
- }
70
-
71
- logger.debug(f"Set user info for {api_key}: {request.state.user}")
92
+ if api_key:
93
+ if self.auth_manager and self._security_available:
94
+ try:
95
+ # Use mcp_security_framework AuthManager
96
+ auth_result = self.auth_manager.authenticate_api_key(api_key)
97
+
98
+ if auth_result.is_valid:
99
+ # Set user info from AuthManager result
100
+ request.state.user = {
101
+ "id": api_key,
102
+ "role": auth_result.roles[0] if auth_result.roles else "guest",
103
+ "roles": auth_result.roles or ["guest"],
104
+ "permissions": getattr(auth_result, 'permissions', ["read"])
105
+ }
106
+ logger.debug(f"✅ Authenticated user with mcp_security_framework: {request.state.user}")
107
+ else:
108
+ # Authentication failed
109
+ request.state.user = {
110
+ "id": None,
111
+ "role": "guest",
112
+ "roles": ["guest"],
113
+ "permissions": ["read"]
114
+ }
115
+ logger.debug(f"❌ Authentication failed for API key: {api_key[:8]}...")
116
+ except Exception as e:
117
+ logger.warning(f"⚠️ AuthManager error: {e}, falling back to basic auth")
118
+ self._security_available = False
119
+
120
+ if not self._security_available:
121
+ # Fallback to basic API key handling
122
+ if api_key in getattr(self, 'api_keys', {}):
123
+ user_role = self.api_keys[api_key]
124
+
125
+ # Get permissions for this role from roles file if available
126
+ role_permissions = ["read"] # default permissions
127
+ if hasattr(self, 'roles_config') and self.roles_config and user_role in self.roles_config:
128
+ role_permissions = self.roles_config[user_role].get("permissions", ["read"])
129
+
130
+ # Set user info in request.state
131
+ request.state.user = {
132
+ "id": api_key,
133
+ "role": user_role,
134
+ "roles": [user_role],
135
+ "permissions": role_permissions
136
+ }
137
+
138
+ logger.debug(f"✅ Authenticated user with basic auth: {request.state.user}")
139
+ else:
140
+ # API key not found
141
+ request.state.user = {
142
+ "id": None,
143
+ "role": "guest",
144
+ "roles": ["guest"],
145
+ "permissions": ["read"]
146
+ }
147
+ logger.debug(f"❌ API key not found: {api_key[:8]}...")
72
148
  else:
73
- # Set default guest user info
149
+ # No API key provided - guest access
74
150
  request.state.user = {
75
151
  "id": None,
76
152
  "role": "guest",
77
153
  "roles": ["guest"],
78
154
  "permissions": ["read"]
79
155
  }
80
-
81
- logger.debug("Set default guest user info")
156
+ logger.debug("ℹ️ No API key provided, using guest access")
82
157
 
83
158
  return await call_next(request)
@@ -175,7 +175,7 @@ class Config:
175
175
  "renewal_threshold_days": 30
176
176
  },
177
177
  "permissions": {
178
- "enabled": False,
178
+ "enabled": True,
179
179
  "roles_file": None,
180
180
  "default_role": "guest",
181
181
  "admin_role": "admin",
@@ -33,12 +33,33 @@ class ProtocolManager:
33
33
 
34
34
  def _load_config(self):
35
35
  """Load protocol configuration from config."""
36
- # Use provided config or fallback to global config
36
+ # Use provided config or fallback to global config; normalize types
37
37
  current_config = self.app_config if self.app_config is not None else config.get_all()
38
-
38
+ logger.info(f"ProtocolManager._load_config - current_config type: {type(current_config)}")
39
+
40
+ if not hasattr(current_config, 'get'):
41
+ # Not a dict-like config, fallback to global
42
+ logger.info(f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config")
43
+ current_config = config.get_all()
44
+
45
+ logger.info(f"ProtocolManager._load_config - final current_config type: {type(current_config)}")
46
+ if hasattr(current_config, 'get'):
47
+ logger.info(f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}")
48
+
39
49
  # Get protocols configuration
40
- self.protocols_config = current_config.get("protocols", {})
41
- self.enabled = self.protocols_config.get("enabled", True)
50
+ logger.info(f"ProtocolManager._load_config - before getting protocols")
51
+ try:
52
+ self.protocols_config = current_config.get("protocols", {})
53
+ logger.info(f"ProtocolManager._load_config - protocols_config type: {type(self.protocols_config)}")
54
+ if hasattr(self.protocols_config, 'get'):
55
+ logger.info(f"ProtocolManager._load_config - protocols_config is dict-like")
56
+ else:
57
+ logger.info(f"ProtocolManager._load_config - protocols_config is NOT dict-like: {repr(self.protocols_config)}")
58
+ except Exception as e:
59
+ logger.info(f"ProtocolManager._load_config - ERROR getting protocols: {e}")
60
+ self.protocols_config = {}
61
+
62
+ self.enabled = self.protocols_config.get("enabled", True) if hasattr(self.protocols_config, 'get') else True
42
63
 
43
64
  # Get SSL configuration to determine allowed protocols
44
65
  ssl_enabled = self._is_ssl_enabled(current_config)
@@ -162,7 +183,14 @@ class ProtocolManager:
162
183
  Protocol configuration dictionary
163
184
  """
164
185
  protocol_lower = protocol.lower()
165
- return self.protocols_config.get(protocol_lower, {}).copy()
186
+ cfg = self.protocols_config.get(protocol_lower, {})
187
+ # Ensure dict type
188
+ if isinstance(cfg, dict):
189
+ try:
190
+ return cfg.copy()
191
+ except Exception:
192
+ return {}
193
+ return {}
166
194
 
167
195
  def validate_url_protocol(self, url: str) -> Tuple[bool, Optional[str]]:
168
196
  """
@@ -13,4 +13,4 @@ Examples include:
13
13
  For detailed documentation, see the main README.md file.
14
14
  """
15
15
 
16
- __version__ = "6.2.18"
16
+ __version__ = "6.2.21"
@@ -36,7 +36,18 @@ def generate_http_token_config(port: int = 8001) -> Dict[str, Any]:
36
36
  "ssl": {"enabled": False},
37
37
  "security": {
38
38
  "enabled": True,
39
- "auth": {"enabled": True, "methods": ["api_key"]},
39
+ "auth": {
40
+ "enabled": True,
41
+ "methods": ["api_key"],
42
+ # Map API tokens to roles for testing
43
+ "api_keys": {
44
+ "test-token-123": "admin",
45
+ "user-token-456": "user",
46
+ "readonly-token-123": "readonly",
47
+ "guest-token-123": "guest",
48
+ "proxy-token-123": "proxy"
49
+ }
50
+ },
40
51
  "permissions": {"enabled": True, "roles_file": "./roles.json"}
41
52
  },
42
53
  "registration": {
@@ -82,7 +93,17 @@ def generate_https_token_config(port: int = 8003) -> Dict[str, Any]:
82
93
  },
83
94
  "security": {
84
95
  "enabled": True,
85
- "auth": {"enabled": True, "methods": ["api_key"]},
96
+ "auth": {
97
+ "enabled": True,
98
+ "methods": ["api_key"],
99
+ "api_keys": {
100
+ "test-token-123": "admin",
101
+ "user-token-456": "user",
102
+ "readonly-token-123": "readonly",
103
+ "guest-token-123": "guest",
104
+ "proxy-token-123": "proxy"
105
+ }
106
+ },
86
107
  "permissions": {"enabled": True, "roles_file": "./roles.json"}
87
108
  },
88
109
  "registration": {
@@ -104,7 +125,7 @@ def generate_mtls_no_roles_config(port: int = 8004) -> Dict[str, Any]:
104
125
  "enabled": True,
105
126
  "cert_file": "./certs/localhost_server.crt",
106
127
  "key_file": "./keys/localhost_server.key",
107
- "ca_cert": "./certs/mcp_proxy_adapter_test_ca_ca.crt",
128
+ "ca_cert": "./certs/mcp_proxy_adapter_ca_ca.crt",
108
129
  "verify_client": True
109
130
  },
110
131
  "security": {
@@ -122,7 +143,7 @@ def generate_mtls_with_roles_config(port: int = 8005) -> Dict[str, Any]:
122
143
  "enabled": True,
123
144
  "cert_file": "./certs/localhost_server.crt",
124
145
  "key_file": "./keys/localhost_server.key",
125
- "ca_cert": "./certs/mcp_proxy_adapter_test_ca_ca.crt",
146
+ "ca_cert": "./certs/mcp_proxy_adapter_ca_ca.crt",
126
147
  "verify_client": True
127
148
  },
128
149
  "registration": {
@@ -160,7 +181,7 @@ def generate_roles_config() -> Dict[str, Any]:
160
181
  "heartbeat",
161
182
  "discover"
162
183
  ],
163
- "tokens": []
184
+ "tokens": ["test-token-123"]
164
185
  },
165
186
  "user": {
166
187
  "description": "User role with limited access",
@@ -172,7 +193,7 @@ def generate_roles_config() -> Dict[str, Any]:
172
193
  "heartbeat",
173
194
  "discover"
174
195
  ],
175
- "tokens": []
196
+ "tokens": ["user-token-456"]
176
197
  },
177
198
  "readonly": {
178
199
  "description": "Read-only role",
@@ -180,7 +201,7 @@ def generate_roles_config() -> Dict[str, Any]:
180
201
  "read",
181
202
  "discover"
182
203
  ],
183
- "tokens": []
204
+ "tokens": ["readonly-token-123"]
184
205
  },
185
206
  "guest": {
186
207
  "description": "Guest role with read-only access",
@@ -188,7 +209,7 @@ def generate_roles_config() -> Dict[str, Any]:
188
209
  "read",
189
210
  "discover"
190
211
  ],
191
- "tokens": []
212
+ "tokens": ["guest-token-123"]
192
213
  },
193
214
  "proxy": {
194
215
  "description": "Proxy role for registration",
@@ -198,7 +219,7 @@ def generate_roles_config() -> Dict[str, Any]:
198
219
  "heartbeat",
199
220
  "discover"
200
221
  ],
201
- "tokens": []
222
+ "tokens": ["proxy-token-123"]
202
223
  }
203
224
  }
204
225
  def generate_all_configs(output_dir: str) -> None:
@@ -19,7 +19,7 @@ from datetime import datetime, timedelta
19
19
 
20
20
  from fastapi import FastAPI, HTTPException
21
21
  from pydantic import BaseModel
22
- import uvicorn
22
+ from mcp_proxy_adapter.core.server_adapter import UnifiedServerRunner
23
23
 
24
24
 
25
25
  # Simple in-memory storage for registered adapters
@@ -130,13 +130,15 @@ def main() -> None:
130
130
  print(" POST /proxy/heartbeat - Heartbeat from adapter")
131
131
  print("⚡ Press Ctrl+C to stop\n")
132
132
 
133
- # Run server
134
- uvicorn.run(
133
+ # Run server via unified runner (hypercorn under the hood)
134
+ runner = UnifiedServerRunner()
135
+ runner.run_server(
135
136
  app,
136
- host=args.host,
137
- port=args.port,
138
- log_level=args.log_level,
139
- access_log=True
137
+ {
138
+ "host": args.host,
139
+ "port": args.port,
140
+ "log_level": args.log_level,
141
+ },
140
142
  )
141
143
 
142
144