10-Step Production Security Checklist
A security researcher demonstrated full RCE on a default FastMCP setup. 66% of MCP servers have security code smells. Don't be one of them.
The 10-Point Security Checklist
Every item below addresses a real attack vector documented in the MCP security landscape.
1. Authentication Required
Risk: FastMCP's default is no auth. HTTP transport without auth = unauthenticated RCE endpoint on the public internet.
from fastmcp.server.auth import BearerAuthProvider
import os
auth = BearerAuthProvider(
token=os.environ["MCP_API_TOKEN"],
jwt_secret=os.environ.get("JWT_SECRET"),
)
mcp = FastMCP("SecureServer", auth=auth)
2. TLS Everywhere
Risk: FastMCP does not handle TLS itself. Use nginx or a load balancer for TLS termination. Never run http:// in production.
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/mcp.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.yourcompany.com/privkey.pem;
location /mcp { proxy_pass http://127.0.0.1:8000; }
}
3. Path Validation
Risk: If your tools access the filesystem, validate paths against directory traversal (../).
import os
SAFE_DIR = "/data/documents"
@mcp.tool()
def read_file(path: str) -> str:
resolved = os.path.realpath(os.path.join(SAFE_DIR, path))
if not resolved.startswith(SAFE_DIR):
raise ValueError("Access denied: path traversal detected")
with open(resolved) as f:
return f.read()
4. Rate Limiting
Risk: Without limits, a malicious or misbehaving agent can exhaust your server.
limit_req_zone $binary_remote_addr zone=mcp:10m rate=30r/m;
location /mcp {
limit_req zone=mcp burst=10 nodelay;
proxy_pass http://127.0.0.1:8000;
}
5. Input Sanitization
Risk: All tool parameters arrive as JSON from an LLM. Never pass raw input to shell commands or SQL queries.
from pydantic import BaseModel, Field, field_validator
import shlex, subprocess
class RestartServiceInput(BaseModel):
service_name: str = Field(max_length=64)
@field_validator("service_name")
@classmethod
def no_shell_chars(cls, v):
if any(c in v for c in [";", "&", "|", "$", "`"]):
raise ValueError("Invalid service name")
return v
@mcp.tool()
def restart_service(input: RestartServiceInput) -> str:
# Safe: shlex.quote + no shell=True
subprocess.run(["systemctl", "restart", input.service_name], capture_output=True)
return "ok"
6. CORS Restrictions
Never use allow_origins=["*"] in production. Include mcp-session-id in expose_headers or browser clients silently fail.
app = mcp.http_app(
cors_allow_origins=["https://your-app.com"],
cors_expose_headers=["mcp-session-id"],
)
7. Secrets Management
Risk: The Docker MCP security analysis found plaintext secrets visible in process lists across thousands of installations.
# docker-compose.yml — environment from .env file, never commit secrets
environment:
- MCP_API_TOKEN=${MCP_API_TOKEN}
- JWT_SECRET=${JWT_SECRET}
8. Non-Root Container
RUN useradd -m mcpuser
USER mcpuser
9. Tool-Level RBAC
@mcp.tool(auth=["admin"])
def delete_record(record_id: str) -> str:
"""Delete a record. Admin only."""
...
10. Audit Logging
mcp = FastMCP(
"AuditedServer",
auth=auth,
instrumentation="opentelemetry", # Native OTEL support
)
FAQ
Does adding auth slow down my MCP server?
Negligibly. Bearer token validation is a hash comparison (O(1)). JWT with jwt_secret adds ~1ms per request. The real latency is in token_store roundtrips (Redis <1ms). For 99% of deployments, auth overhead is invisible compared to LLM inference time.
What if I already have an API gateway (Kong, Traefik, AWS API Gateway)?
You can offload items 2 (TLS), 4 (Rate Limiting), and 6 (CORS) to the gateway. Keep items 1 (Auth), 3 (Path Validation), 5 (Input Sanitization), and 9 (RBAC) at the FastMCP layer — the gateway can't enforce tool-level authorization or path validation inside your tool code.
Does this checklist apply to other MCP SDKs (Python MCP, TypeScript MCP)?
Mostly yes. Items 2-8 and 10 are transport-layer concerns (nginx, Docker, secrets) that apply regardless of SDK. Items 1, 9 (auth/RBAC) use FastMCP-specific APIs but the patterns are portable. The security research cited in the footer covers the broader MCP ecosystem.
How do I validate this checklist actually works?
Run the checklist in reverse order on a staging instance: start with audit logging (10) to capture what happens, then test RBAC bypass (9), then attempt CORS misconfig (6), then path traversal (3). The Production Manual includes a full penetration-testing script that automates all 10 checks against your endpoint.
Full Security Audit — Save Hours of Audit Prep
The Production Manual includes all 10 checklist items with expanded patterns: enterprise RBAC with Cerbos/OPA integration, audit trail setup, incident response runbook, and an automated pen-test script that validates every item against your live endpoint.
From $39, lifetime updates. Free 14-day refund, no lock-in.
Get the Production Manual