Security: - Remove /mnt/ from _ALLOWED_LOG_PREFIXES to prevent Unraid share exposure - Add early .. detection for disk/logs and live/log_tail path validation - Add /boot/ prefix restriction for flash_backup source_path - Use hmac.compare_digest for timing-safe API key verification in server.py - Gate include_traceback on DEBUG log level (no tracebacks in production) Correctness: - Re-raise CredentialsNotConfiguredError in health check instead of swallowing - Fix ups_device query (remove non-existent nominalPower/currentPower fields) Best practices (BP-01, BP-05, BP-06): - Add # noqa: ASYNC109 to timeout params in _handle_live and unraid() - Fix start_array* → start_array in docstring (not in ARRAY_DESTRUCTIVE) - Remove from __future__ import annotations from snapshot.py - Replace import-time UNRAID_API_KEY/URL bindings with _settings.ATTR pattern in manager.py, snapshot.py, utils.py, diagnostics.py — fixes stale binding after apply_runtime_config() post-elicitation (BP-05) CI/CD: - Add .github/workflows/ci.yml (5-job pipeline: lint, typecheck, test, version-sync, audit) - Add fail_under = 80 to [tool.coverage.report] - Add version sync check to scripts/validate-marketplace.sh Documentation: - Sync plugin.json version 1.1.1 → 1.1.2 with pyproject.toml - Update CLAUDE.md: 3 tools, system domain count 18, scripts comment fix - Update README.md: 3 tools, security notes - Update docs/AUTHENTICATION.md: H1 title fix - Add UNRAID_CREDENTIALS_DIR to .env.example Bump: 1.1.1 → 1.1.2 Co-Authored-By: Claude <noreply@anthropic.com>
7.2 KiB
Authentication Setup Guide
This document covers both Google OAuth 2.0 and API key bearer token authentication for the Unraid MCP HTTP server. It explains how to protect the server using FastMCP's built-in GoogleProvider for OAuth, or a static bearer token for headless/machine access.
Overview
By default the MCP server is open — any client on the network can call tools. Setting three environment variables enables Google OAuth 2.1 authentication: clients must complete a Google login flow before the server will execute any tool.
OAuth state (issued tokens, refresh tokens) is persisted to an encrypted file store at ~/.local/share/fastmcp/oauth-proxy/, so sessions survive server restarts when UNRAID_MCP_JWT_SIGNING_KEY is set.
Transport requirement: OAuth only works with HTTP transports (
streamable-httporsse). It has no effect onstdio— the server logs a warning if you configure both.
Prerequisites
- Google account with access to Google Cloud Console
- MCP server reachable at a known URL from your browser (LAN IP, Tailscale IP, or public domain)
UNRAID_MCP_TRANSPORT=streamable-http(the default)
Step 1: Create a Google OAuth Client
- Open Google Cloud Console → APIs & Services → Credentials
- Click Create Credentials → OAuth 2.0 Client ID
- Application type: Web application
- Name: anything (e.g.
Unraid MCP) - Authorized redirect URIs — add exactly:
Replace
http://<your-server-ip>:6970/auth/callback<your-server-ip>with the IP/hostname your browser uses to reach the MCP server (e.g.10.1.0.2,100.x.x.xfor Tailscale, or a domain name). - Click Create — copy the Client ID and Client Secret
Step 2: Configure Environment Variables
Add these to ~/.unraid-mcp/.env (the canonical credential file for all runtimes):
# Google OAuth (optional — enables authentication)
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-your-client-secret
# Public base URL of this MCP server (must match the redirect URI above)
UNRAID_MCP_BASE_URL=http://10.1.0.2:6970
# Stable JWT signing key — prevents token invalidation on server restart
# Generate one: python3 -c "import secrets; print(secrets.token_hex(32))"
UNRAID_MCP_JWT_SIGNING_KEY=your-64-char-hex-string
All four variables at once (copy-paste template):
cat >> ~/.unraid-mcp/.env <<'EOF'
# Google OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
UNRAID_MCP_BASE_URL=http://10.1.0.2:6970
UNRAID_MCP_JWT_SIGNING_KEY=
EOF
Then fill in the blanks.
Step 3: Generate a Stable JWT Signing Key
Without UNRAID_MCP_JWT_SIGNING_KEY, FastMCP derives a key on startup. Any server restart invalidates all existing tokens and forces every client to re-authenticate.
Generate a stable key once:
python3 -c "import secrets; print(secrets.token_hex(32))"
Paste the output into UNRAID_MCP_JWT_SIGNING_KEY. This value never needs to change unless you intentionally want to invalidate all sessions.
Step 4: Restart the Server
# Docker Compose
docker compose restart unraid-mcp
# Direct / uv
uv run unraid-mcp-server
On startup you should see:
INFO [SERVER] Google OAuth enabled — base_url=http://10.1.0.2:6970, redirect_uri=http://10.1.0.2:6970/auth/callback
How Authentication Works
- An MCP client connects to
http://<server>:6970/mcp - The server responds with a
401 Unauthorizedand an OAuth authorization URL - The client opens the URL in a browser; the user logs in with Google
- Google redirects to
<UNRAID_MCP_BASE_URL>/auth/callbackwith an authorization code - FastMCP exchanges the code for tokens, issues a signed JWT, and returns it to the client
- The client includes the JWT in subsequent requests — the server validates it without hitting Google again
- Tokens persist to
~/.local/share/fastmcp/oauth-proxy/— sessions survive server restarts
Environment Variable Reference
| Variable | Required | Default | Description |
|---|---|---|---|
GOOGLE_CLIENT_ID |
For OAuth | "" |
OAuth 2.0 Client ID from Google Cloud Console |
GOOGLE_CLIENT_SECRET |
For OAuth | "" |
OAuth 2.0 Client Secret from Google Cloud Console |
UNRAID_MCP_BASE_URL |
For OAuth | "" |
Public base URL of this server — must match the authorized redirect URI |
UNRAID_MCP_JWT_SIGNING_KEY |
Recommended | auto-derived | Stable 32+ char secret for JWT signing — prevents token invalidation on restart |
OAuth is activated only when all three of GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and UNRAID_MCP_BASE_URL are non-empty. Omit any one to run without authentication.
Disabling OAuth
Remove (or empty) GOOGLE_CLIENT_ID from ~/.unraid-mcp/.env and restart. The server reverts to unauthenticated mode and logs:
WARNING [SERVER] No authentication configured — MCP server is open to all clients on the network.
Troubleshooting
redirect_uri_mismatch from Google
The redirect URI in Google Cloud Console must exactly match <UNRAID_MCP_BASE_URL>/auth/callback — same scheme, host, port, and path. Trailing slashes matter.
Tokens invalidated after restart
Set UNRAID_MCP_JWT_SIGNING_KEY to a stable secret (see Step 3). Without it, FastMCP generates a new key on every start.
stdio transport warning
OAuth requires an HTTP transport. Set UNRAID_MCP_TRANSPORT=streamable-http (the default) or sse.
Client cannot reach the callback URL
UNRAID_MCP_BASE_URL must be the address your browser uses to reach the server — not localhost or 0.0.0.0. Use the LAN IP, Tailscale IP, or a domain name.
OAuth configured but server not starting
Check logs/unraid-mcp.log or docker compose logs unraid-mcp for startup errors.
API Key Authentication (Alternative / Combined)
For machine-to-machine access (scripts, CI, other agents) without a browser-based OAuth flow, set UNRAID_MCP_API_KEY:
# In ~/.unraid-mcp/.env
UNRAID_MCP_API_KEY=your-secret-token
Clients present it as a standard bearer token:
Authorization: Bearer your-secret-token
Combining with Google OAuth: set both GOOGLE_CLIENT_ID and UNRAID_MCP_API_KEY. The server activates MultiAuth and accepts either method — Google OAuth for interactive clients, API key for headless clients.
Reusing the Unraid API key: you can set UNRAID_MCP_API_KEY to the same value as UNRAID_API_KEY for simplicity. The two vars are kept separate so each concern has its own name.
Standalone API key (no Google OAuth): set only UNRAID_MCP_API_KEY. The server validates bearer tokens directly with no OAuth redirect flow.
Security Notes
- OAuth protects the MCP HTTP interface — the Unraid GraphQL API itself still uses
UNRAID_API_KEY - OAuth state files at
~/.local/share/fastmcp/oauth-proxy/should be on a private filesystem; do not expose them - Restrict Google OAuth to specific accounts via the Google Cloud Console OAuth consent screen → Test users if you don't want to publish the app
UNRAID_MCP_JWT_SIGNING_KEYis a credential — store it in~/.unraid-mcp/.env(mode 600), never in source control