# User Management System Setup Guide This guide explains how to integrate the user management system into your MCP Gateway, enabling per-user API key generation and MCP access control. ## Overview The user management system provides: - **User Creation & Management**: Create and manage users, enable/disable accounts - **API Key Generation**: Generate unique API keys with optional TTL (time-to-live) - **MCP Access Control**: Allow/block specific MCPs for each user (e.g., some users access only ERPNext, others access Wave + TrueNAS) - **Persistent Storage**: User data stored in JSON file, survives container restarts - **Web Dashboard**: Intuitive UI for managing users and API keys ## Files Created 1. **user_management.py** - Core user/API key management logic 2. **user_routes.py** - REST API endpoints for user management 3. **user_dashboard_ui.py** - Web dashboard with Vue.js UI 4. **gateway_proxy_user_integration.py** - Integration instructions ## Installation Steps ### Step 1: Copy Files The files are already created in `gateway-proxy/`: - `user_management.py` - `user_routes.py` - `user_dashboard_ui.py` ### Step 2: Update gateway_proxy.py Add the import at line 33 (after existing imports): ```python 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 ) from user_dashboard_ui import user_management_dashboard ``` ### Step 3: Update validate_bearer_token() Function Replace the `validate_bearer_token()` function (around line 254) with: ```python 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 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 4: Add MCP Access Control to handle_mcp() In the `handle_mcp()` function, after retrieving `token_info`, add this check: ```python # Check MCP access control if token_info and 'user' in token_info and token_info.get('client_id') == 'api-key': mcp_allowed = token_info.get('mcp_allowed', []) mcp_blocked = token_info.get('mcp_blocked', []) # Check if user can access any backend (basic check) if not mcp_allowed and not mcp_blocked: # User has no restrictions, allow all pass elif mcp_blocked and len(mcp_blocked) == len(BACKENDS): return JSONResponse( {'error': 'access_denied', 'message': 'All MCPs are blocked for your user'}, status_code=403 ) ``` ### Step 5: Update Routes List Add these routes to the routes list before creating the app (around line 1012): ```python routes = [ # ... existing well-known and OAuth routes ... # MCP endpoint Route("/mcp", handle_mcp, methods=["GET", "HEAD", "POST", "DELETE"]), # Monitoring Route("/health", health, methods=["GET"]), Route("/status", status, methods=["GET"]), # Dashboard Route("/dashboard", dashboard, methods=["GET"]), Route("/dashboard/status", dashboard_status, methods=["GET"]), # User Management - Enhanced Dashboard Route("/admin", user_management_dashboard, methods=["GET"]), # User Management API 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 6: Update docker-compose.yml Ensure the gateway service has a data volume for persistent storage: ```yaml services: mcp-gateway: image: mcp-gateway:latest build: context: ./gateway-proxy dockerfile: Dockerfile container_name: mcp-gateway ports: - "4444:4444" environment: # ... existing environment variables ... USERS_DB_PATH: /data/users.json volumes: - ./data:/data - ./gateway-proxy:/app depends_on: # ... existing dependencies ... ``` ### Step 7: Create Data Directory ```bash mkdir -p /sessions/vigilant-elegant-ramanujan/mnt/MCP\ Servers/mcp-gateway/data ``` ### Step 8: Restart Gateway ```bash docker-compose down docker-compose up -d mcp-gateway ``` ## Usage ### Access the Dashboard Open your browser to: ``` http://10.0.0.25:4444/admin ``` ### Create a User via API ```bash curl -X POST http://10.0.0.25:4444/users \ -H "Content-Type: application/json" \ -d '{ "username": "alice", "email": "alice@example.com", "description": "Engineering team" }' ``` ### Generate an API Key ```bash curl -X POST http://10.0.0.25:4444/users/alice/keys \ -H "Content-Type: application/json" \ -d '{ "key_name": "production-key", "ttl_days": 90 }' ``` Response: ```json { "status": "created", "username": "alice", "api_key": "mcpgw_...", "note": "Save this key immediately — it will not be shown again" } ``` ### Configure MCP Access ```bash curl -X PUT http://10.0.0.25:4444/users/alice/mcp-access \ -H "Content-Type: application/json" \ -d '{ "allowed_mcps": ["erpnext", "wave"], "blocked_mcps": [] }' ``` This allows alice to access only ERPNext and Wave Finance MCPs. ### Use the API Key ```bash curl -X POST http://10.0.0.25:4444/mcp \ -H "Authorization: Bearer mcpgw_..." \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test-client", "version": "1.0"} } }' ``` ## Access Control Examples ### Example 1: Limited Access User Create a user with access to only ERPNext: ```bash # Create user curl -X POST http://10.0.0.25:4444/users \ -H "Content-Type: application/json" \ -d '{"username": "erp-user", "description": "ERP access only"}' # Generate key curl -X POST http://10.0.0.25:4444/users/erp-user/keys \ -H "Content-Type: application/json" \ -d '{"key_name": "erp-only"}' # Restrict to ERPNext curl -X PUT http://10.0.0.25:4444/users/erp-user/mcp-access \ -H "Content-Type: application/json" \ -d '{"allowed_mcps": ["erpnext"]}' ``` ### Example 2: Block Specific MCPs Create a user with access to everything except Home Assistant: ```bash curl -X PUT http://10.0.0.25:4444/users/alice/mcp-access \ -H "Content-Type: application/json" \ -d '{"blocked_mcps": ["homeassistant"]}' ``` ### Example 3: Revoke an API Key ```bash curl -X POST http://10.0.0.25:4444/keys/revoke \ -H "Content-Type: application/json" \ -d '{"api_key": "mcpgw_..."}' ``` ## Database Schema User data is stored in `/data/users.json` with the following structure: ```json { "users": { "alice": { "user_id": "abc123...", "email": "alice@example.com", "description": "Engineering team", "created_at": "2026-03-31T12:00:00.000000", "enabled": true, "api_keys": ["hash1", "hash2"], "mcp_allowed": ["erpnext", "wave"], "mcp_blocked": [], "metadata": {} } }, "api_keys": { "hash1": { "user_id": "abc123...", "username": "alice", "key_name": "prod-key", "created_at": "2026-03-31T12:00:00.000000", "expires_at": null, "revoked": false } } } ``` ## Security Notes 1. **API Keys are Hashed**: Only SHA256 hashes are stored, never the actual key 2. **One-Time Display**: Keys are shown only once during generation 3. **TTL Support**: Keys can expire after N days 4. **Revocation**: Keys can be revoked at any time 5. **Per-User Access Control**: Each user has independent MCP restrictions ## Troubleshooting ### Users/Keys Not Persisting After Restart Check that: 1. `/data` directory exists and is mounted in docker-compose.yml 2. `/data` directory has write permissions 3. `USERS_DB_PATH=/data/users.json` is set in environment ### API Key Not Working 1. Verify key hasn't been revoked: Check in dashboard 2. Verify key hasn't expired: Check `expires_at` timestamp 3. Verify user is enabled: Check `enabled` field in dashboard 4. Check MCP access: Verify the user has access to the MCP they're trying to use ## Next Steps - Configure additional users for different teams/roles - Set up automated key rotation policies - Monitor API key usage via the dashboard - Integrate with your CI/CD for automated deployments