Skip to main content
MCPHub reads the following environment variables at startup. The authoritative list is whatever appears under process.env.* in src/; this page summarizes everything currently read by the code on main.

Core application

Custom Smart Routing URL

For example, with PORT=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

JWT_SECRET must be set to a persistent, high-entropy value (≥ 32 random bytes) in staging and production. If it is left unset, MCPHub generates a new random secret on every process start, which means: every restart invalidates all outstanding sessions and bearer tokens; horizontally-scaled instances cannot share sessions because each replica signs with its own secret; and CI / container restarts silently log everyone out. Generate one with openssl rand -hex 32 and store it in your secret manager. Treat it like any other long-lived cryptographic key — rotation requires invalidating outstanding JWTs.

Better Auth (optional social login)

Better Auth is initialized once at process startup in src/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:
  1. BETTER_AUTH_* environment variables
  2. systemConfig.auth.betterAuth (from mcp_settings.json or the database-backed system config)
  3. Built-in defaults
Provider client credentials remain environment-variable only.
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.
See Database Configuration for end-to-end setup.

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

  1. Never commit secrets — .env* files are gitignored by default; keep it that way.
  2. Always set JWT_SECRET explicitly in production.
  3. Rotate bearer keys (/api/auth/keys) and OAuth client secrets periodically.
  4. Use Docker / Kubernetes secrets for container deployments instead of plain -e.