process.env.* in src/; this page summarizes everything currently read by the code on main.
Core application
Custom Smart Routing URL
For example, withPORT=6001, BASE_PATH=/mcp_manage and SMART_ROUTING_PATH=my_smart, connect using Streamable HTTP at http://localhost:6001/mcp_manage/mcp/my_smart. Append /<group> to restrict Smart Routing to a group, or prepend /<user> before /mcp for a user-scoped route. The same alias also works under /sse for legacy clients.
The configured segment is reserved for Smart Routing. Startup rejects existing server/group name or group ID conflicts, and configuration writes reject new conflicts. Change the segment or rename the conflicting target first. Changing the segment requires a restart and updating clients using the previous custom URL; $smart remains available for compatibility, including CLI calls. This setting does not change authentication or permissions.
Authentication
Better Auth (optional social login)
Better Auth is initialized once at process startup insrc/betterAuth.ts. Because of that, changing any Better Auth setting still requires a restart.
For non-secret Better Auth settings, MCPHub resolves values in this order:
BETTER_AUTH_*environment variablessystemConfig.auth.betterAuth(frommcp_settings.jsonor the database-backed system config)- Built-in defaults
Better Auth currently requires PostgreSQL-backed storage in MCPHub. In practice that means
DB_URL must be configured; file-only mode does not support Better Auth sessions.
You can still store the non-secret Better Auth settings in
systemConfig.auth.betterAuth, but BETTER_AUTH_* variables now override those values at startup. A full env-only local OIDC example looks like this:
Forward auth
Forward auth trusts a JWT issued to users by an upstream gateway and verifies it against the identity provider’s JWKS. See Authentication → Forward auth for the behavior. Values resolve in this order:FORWARD_AUTH_* environment variables, then systemConfig.auth.forwardAuth, then built-in defaults. Settings are read per request, so no restart is needed.
Storage
MCPHub picks file or database storage at boot:DB_POOL_SIZE is a per-pool limit. MCPHub opens one pool for TypeORM and, when Better Auth is enabled, a second one for Better Auth, each sized to DB_POOL_SIZE. When both are in use, budget roughly 2 × DB_POOL_SIZE PostgreSQL connections per replica (for example DB_POOL_SIZE=20 → about 40), plus headroom for other clients and ops tooling against the same database.This is the combined configured pool capacity, not a strict process-wide cap. During an automatic reconnection, the old pool is torn down with DB_DESTROY_TIMEOUT; if that teardown times out, connections from the old pool may linger briefly while the new pool is already open.Smart Routing & embeddings
Smart Routing performs vector search over upstream tools to surface only the few most relevant tools for a given query. It requires Postgres + pgvector and an embedding endpoint.OpenAI
Azure OpenAI
Environment variables win over the dashboard. Every setting above overrides the matching field saved in the dashboard. Resolution order is environment variable → dashboard setting → built-in default, so a stale value left in
.env silently shadows a key you just pasted into the UI — embeddings then fail with an authentication error while the form still shows the new key (issue #642).The dashboard now reports this: affected fields carry a warning naming the environment variable that is actually in use. To switch to the dashboard value, remove the variable from the environment and restart.Smart Routing → Enabled and DB URL follow the same order but are reflected directly by the UI instead of a warning — the toggle mirrors the env var, and the URL field renders a ${DB_URL} placeholder.MCPRouter (optional upstream catalog)
Tool call guard (optional)
Configuration examples
Development
Production with database + Smart Routing
Loading order
At startup MCPHub reads one file,.env in the working directory. .env.local and .env.{NODE_ENV} (e.g. .env.production) are not read.
A variable already set in the process environment (your shell, Docker -e / env_file, a Kubernetes manifest) takes precedence; .env never overrides it.
Values in .env are used as written: ${VAR} references inside .env are not expanded. ${VAR} expansion is available in mcp_settings.json instead; see MCP Settings.
Security best practices
- Never commit secrets —
.env*files are gitignored by default; keep it that way. - Always set
JWT_SECRETexplicitly in production. - Rotate bearer keys (
/api/auth/keys) and OAuth client secrets periodically. - Use Docker / Kubernetes secrets for container deployments instead of plain
-e.