mcp-servers/mcp-gateway/gateway-proxy/gateway_proxy_user_integration.py

147 lines
5.1 KiB
Python

"""
Integration instructions for user management into gateway_proxy.py
==================================================================
STEP 1: Add import at the top of gateway_proxy.py (after line 32):
-------------------------------------------------------------------
from user_management import user_manager
from user_routes import (
create_user, list_users, get_user, delete_user, toggle_user,
generate_api_key, revoke_api_key, set_mcp_access
)
STEP 2: Modify validate_bearer_token() function (around line 254):
------------------------------------------------------------------
Replace the validate_bearer_token function with:
def validate_bearer_token(request: Request) -> dict | None:
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
return None
token = auth_header[7:]
# Check static API key first (persistent, survives restarts)
if STATIC_API_KEY and token == STATIC_API_KEY:
return {"client_id": "static", "scope": "mcp:tools", "user": "static"}
# Check user API key
user_info = user_manager.validate_api_key(token)
if user_info:
return {
"client_id": "api-key",
"scope": "mcp:tools",
"user": user_info['username'],
"user_id": user_info['user_id'],
"mcp_allowed": user_info['mcp_allowed'],
"mcp_blocked": user_info['mcp_blocked']
}
# Check OAuth token
token_hash = _hash(token)
info = ACCESS_TOKENS.get(token_hash)
if not info:
return None
if info["expires_at"] < time.time():
del ACCESS_TOKENS[token_hash]
return None
return info
STEP 3: Modify handle_mcp() function to filter by user MCP access:
------------------------------------------------------------------
In the handle_mcp() function, after getting token info, add:
# Check MCP access control
if token_info and 'user' in token_info:
# Check if user can access this backend
user = token_info.get('user')
mcp_allowed = token_info.get('mcp_allowed', [])
mcp_blocked = token_info.get('mcp_blocked', [])
# Parse which backend is being accessed from params
params = body.get('params', {})
backend_name = params.get('backend') # Should be set by frontend
if backend_name:
if backend_name in mcp_blocked:
return JSONResponse(
{'error': 'access_denied', 'message': f'Access to {backend_name} is blocked'},
status_code=403
)
if mcp_allowed and backend_name not in mcp_allowed:
return JSONResponse(
{'error': 'access_denied', 'message': f'You do not have access to {backend_name}'},
status_code=403
)
STEP 4: Add new routes before building the routes list (before line 1012):
--------------------------------------------------------------------------
Add these route definitions right before the routes list:
# User management routes
Route("/users", create_user, methods=["POST"]),
Route("/users", list_users, methods=["GET"]),
Route("/users/{username}", get_user, methods=["GET"]),
Route("/users/{username}", delete_user, methods=["DELETE"]),
Route("/users/{username}/enable", toggle_user, methods=["PATCH"]),
Route("/users/{username}/keys", generate_api_key, methods=["POST"]),
Route("/users/{username}/mcp-access", set_mcp_access, methods=["PUT"]),
Route("/keys/revoke", revoke_api_key, methods=["POST"]),
STEP 5: Update the routes list (around line 1012):
--------------------------------------------------
Insert the user management routes into the routes list:
routes = [
# ... existing routes ...
# User management (admin endpoints)
Route("/users", create_user, methods=["POST"]),
Route("/users", list_users, methods=["GET"]),
Route("/users/{username}", get_user, methods=["GET"]),
Route("/users/{username}", delete_user, methods=["DELETE"]),
Route("/users/{username}/enable", toggle_user, methods=["PATCH"]),
Route("/users/{username}/keys", generate_api_key, methods=["POST"]),
Route("/users/{username}/mcp-access", set_mcp_access, methods=["PUT"]),
Route("/keys/revoke", revoke_api_key, methods=["POST"]),
# ... rest of routes ...
]
STEP 6: Update docker-compose.yml volume mounts:
-----------------------------------------------
Add a data volume to persist user database:
volumes:
- ./data:/data
- ./gateway-proxy:/app
And in the service, add:
volumes:
- ./data:/data
STEP 7: Optional - Create initial admin user during startup:
----------------------------------------------------------
In the startup() function, add:
async def startup():
# Initialize admin user if not exists
try:
users = user_manager.list_users()
if not any(u['username'] == 'admin' for u in users):
user_manager.create_user('admin', email='admin@localhost', description='Administrator')
admin_key = user_manager.generate_api_key('admin', key_name='initial-setup')
logger.info(f"Created admin user. Initial API key: {admin_key}")
except Exception as e:
logger.warning(f"Could not initialize admin user: {e}")
# ... rest of startup ...
"""
print(__doc__)