Quick Start
Enable strict security mode for production:Security Options
CORS Configuration
By default FrontMCP sends no CORS headers at all. A cross-origin request still reaches the server and is served normally — the browser simply refuses to let the calling page read the response. Non-browser clients (the MCP CLI, an agent runtime, curl) are unaffected: CORS is a browser rule, not server-side access control. If you need to keep callers out, use authentication. If a browser on another origin needs access, say so explicitly:cors: false is the same runtime state as omitting the option — no headers — and exists only to say so explicitly:
Bind Address
Controls which network interface the server listens on. The default is127.0.0.1 — a server that says nothing about security is local-only.
The effective address is resolved in this order, first match wins:
http.security.bindAddressin the server config- The
FRONTMCP_BIND_ADDRESSenvironment variable (all,loopback, or a literal address) - Strict mode —
0.0.0.0for a distributed deployment,127.0.0.1otherwise - Distributed deployment mode —
0.0.0.0 - The default —
127.0.0.1
Containers and VMs
A container publishes a port and expects the process inside to listen on every interface, but a Dockerfile cannot reach into the server’s TypeScript config. Set the environment variable instead — no rebuild required:frontmcp create with the Docker target already set this.
Distributed builds (
frontmcp build --target distributed, which sets FRONTMCP_DEPLOYMENT_MODE=distributed) bind all interfaces automatically — a distributed deployment must be reachable by its peers. Serverless targets (Vercel, Lambda, Cloudflare) never bind a port at all, so this setting does not apply to them.Strict Mode Behavior
Whensecurity.strict: true:
- Standalone mode: binds to
127.0.0.1(loopback only) - Distributed mode: binds to
0.0.0.0(pods need external access)
Explicit Override
DNS Rebinding Protection
Validates the HTTPHost, X-Forwarded-Host and Origin headers against an allowlist. A request naming a host this server does not answer to gets 403 Forbidden — before routing and before the body is read, so the MCP endpoint, the OAuth routes, the SSE transport and any custom route are all covered.
On by default since v1.7.2. You only configure it when the derived default cannot know your hostname.
What the default allows
With noallowedHosts configured, the list is derived from what the process actually listens on:
localhost,127.0.0.1,[::1]— each with and without the bound port- the specific NIC address, when the server binds one
example.com / example.com:80 / example.com:443 compare equal.
Deployments behind a proxy
A server bound to a routable address (0.0.0.0, ::, a specific NIC) is reached under a hostname the process cannot know. FrontMCP does not enforce a derived list there — it logs a warning and leaves host checking off, so upgrading a patch version does not take a proxied deployment offline. Name your public host to turn it on:
FRONTMCP_BIND_ADDRESS in a container:
Semantics
allowedHosts: matched againstHost, and against every hop ofX-Forwarded-Hostwhen present. A poisoned forwarded host is rejected even whenHostitself is valid, because issuer and OAuth-discovery URLs can be derived from it.allowedOrigins: matched againstOrigin, scheme included.- A request with no
Originis allowed through: non-browser clients never send one, and a rebound page always does.
A DNS rebinding attack points an attacker-controlled domain at
127.0.0.1, so the victim’s browser treats a request to a local server as same-origin. Binding to loopback does not help — loopback is the destination — and neither does CORS, because the browser genuinely considers the request same-origin. Validating Host is the server-side defence. See GHSA-mc9g-v2cp-vfff.Request Body Limits
FrontMCP’s Express host applies a default request body limit of'4mb' to
both express.json() and express.urlencoded() — lifting body-parser’s
silent 100KB default, which routinely rejected base64-encoded blobs (PDFs,
DOCXes, large HTML inputs) before they reached MCP tool handlers (issue
#410). Override the limits via the http block on @FrontMcp:
When a request exceeds the configured limit, the adapter returns HTTP 413
with a structured JSON-RPC envelope:
hostFactory users build their own Express app and are
not affected by bodyLimit/urlencodedLimit — those options are
consumed only by the built-in ExpressHostAdapter. Custom-host
deployments must configure their own body limits.
Security Audit Warnings
In production (NODE_ENV=production) or distributed mode, FrontMCP logs security warnings at startup:
CORS_DISABLED and BIND_RESTRICTED — because the defaults are already the safe choice. The audit reports; it never changes behaviour. Use it to check what your configuration actually exposes before going to production.
Production Checklist
- Set explicit
cors.origin(nottrue) — only if a browser on another origin needs access - Set
security.dnsRebindingProtection.allowedHosts(orFRONTMCP_ALLOWED_HOSTS) to your public hostname — on a routable bind the derived default is not enforced - Confirm the bind address: loopback behind a reverse proxy,
FRONTMCP_BIND_ADDRESS=allin a container - Configure TLS termination at the reverse proxy layer
- Set
NODE_ENV=productionfor security audit warnings - Review startup logs for
[Security]warnings - Tune
http.bodyLimitto your largest legitimate payload
Example: Full Production Config
Related
Security Headers & CSP
Content Security Policy, HSTS, and X-Frame-Options
High Availability
Distributed sessions, heartbeat, and session takeover
Redis Setup
Redis connection and session store configuration
Production Build
Build and deploy for production