Settings & env vars

Everything the library reads from your environment or Django settings.

Settings layout — MCP bag

Every 0-mcp setting lives inside a single MCP = {...} dict in settings.py (DRF/Celery-style namespace):

# settings.py
MCP = {
    'CACHE_TTL': 300,
    'CACHE_TTL_ENABLE': True,
    'ENFORCE_TOKEN': True,
    'COOKIE_ID': 'sid',
    'RATE_LIMITS': {...},
}

Inside the bag the MCP_ prefix is redundant — 'MCP_API_KEY_RESOLVER' and 'API_KEY_RESOLVER' resolve to the same setting.

Environment variables

VariableRequiredDescription
REDIS_SERVERYesRedis hostname / address. Requires Redis 6.2 or newer (the framework uses GETEX for sliding session TTLs).
REDIS_DBYesRedis database number
REDIS_PREFIXNoOptional prefix applied to all Redis keys (use to isolate environments on a shared instance)

Django settings

SettingDefaultDescription
DEFAULT_AUTHENTICATEDTrueClass-level default for BaseResource.authenticated. Generated projects (0-mcp init) ship with this set to False so the demo boots without a configured api-key resolver — flip back to True (or override per-resource) before deploying.
COOKIE_ID'sessionid'Cookie name carrying the session id. Used by AuthMiddleware, BaseResource and the OpenAPI security scheme — set once in the bag and every entry point reads the same value.
ALLOWED_ORIGINS[]If set, requests must have an Origin (with Referer fallback) whose host ends with one of these origins
TRUSTED_PROXIES[]CIDRs allowed to set X-Real-IP / X-Forwarded-For
ENFORCE_TOKENFalseRequire X-Token anti-replay header on authenticated requests
TOKEN_MAX_DRIFT_MS30000Maximum clock drift (milliseconds) accepted when validating X-Token. Tighter values reduce the replay window; looser values tolerate slow clocks and event-loop pauses on the client.
CREDENTIAL_PATHS['/forgot', '/change_password', '/signup', '/reset', '/recover', '/register']Path-segment list that triggers the credential-path auto-defense (a tight per-IP rate-limit bucket on top of the regular API limits). Segment-based match — /forgot covers /login/forgot, /user/forgot/..., but not /forgotten. Setting this in your project replaces the framework default (no merge); copy the list to extend. Set to [] to disable.
CREDENTIAL_RATE_LIMIT{'limit': 5, 'window': 30}Per-IP rate limit applied to CREDENTIAL_PATHS. window in seconds. Defaults to 5 hits / 30s — tight enough to break credential-stuffing, loose enough to absorb legitimate retries (resend-email button, NAT-shared offices).
READ_ONLYFalseGlobal read-only gate. When True, every non-GET request returns 405 across all resources (REST + MCP) — overrides per-resource allowed_methods. Useful for safe-by-default deployments and projects generated by 0-mcp init (the default unless you pass --writable).
RATE_LIMITSsensible defaultsSee Rate limiting page
AUTO_SCOPE_CACHE_BY_ACCOUNTTrueAuto-fold self.account_id into the cache key so multi-tenant deployments don't leak cache across tenants. Set to False only on single-tenant deployments that want the legacy key shape. See Cache.
CACHE_TTLNoneProject-level default for BaseResource.cache_ttl (seconds). When unset, the framework default of 120s applies. Resources that declare cache_ttl = N keep their explicit value. See Cache.
CACHE_TTL_ENABLETrueMaster kill switch. When False, every cache=True resource is treated as cache=False at runtime — no read, no write to Redis. Useful for incident response without code edits.
SESSION_TTL1800Sliding TTL (seconds) for cookie-based sessions. Renewed on every authenticated request via Redis GETEX (Redis 6.2+ required).
API_SESSION_TTL300Sliding TTL (seconds) for the API-key → session mapping. Renewed on every authenticated request via Redis GETEX.
MCP_LIST_OMIT_NULLFalseStrip null fields from MCP list_* tool responses to shrink payloads. Useful for agent surfaces where empty fields just consume tokens.
MCP_EDIT_OMIT_NULLFalseSame as MCP_LIST_OMIT_NULL but for get_* / update_* tool responses.
MAX_4XX_PER_MINUTE10Anti-scanner: when an IP returns more than this many 4xx responses in 60s, it is parked in the block list for BLOCK_DURATION_SECONDS.
MAX_4XX_PER_HOUR30Same as MAX_4XX_PER_MINUTE but on a 1-hour window. Hitting either threshold triggers the block.
BLOCK_DURATION_SECONDS86400How long an IP stays in the block list once tripped. Defaults to 24h.
BLOCK_PATTERNSNone (framework baseline)Regex list applied to request paths — known vulnerability scanners are blocked pre-emptively. Pass a list to replace the baseline, [] to disable.
BLOCK_USER_AGENTSNone (framework baseline)Same as BLOCK_PATTERNS but for the User-Agent header.
API_KEY_RESOLVERNoneDotted path (or callable) to a custom API key resolver. Receives the raw key, returns a session dict or None. When unset, the default four-segment-hash resolver is used. (MCP_API_KEY_RESOLVER is also accepted — the prefix is redundant inside the bag.)
DEBUGFalseWhen False, unhandled exceptions become sanitized 500s

Middleware order

In MIDDLEWARE:

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # ... your other middleware ...
    'zeromcp.SecurityMiddleware',     # blocks scanners early
    'zeromcp.AuthMiddleware',         # handled by dispatch, but kept for non-resource views
    'zeromcp.ExceptionMiddleware',    # catches HTTPException
]

Database router (multi-tenant)

DATABASE_ROUTERS = ['zeromcp.DBRouter']

Required only if you use multi-tenant.

0-mcp by Stamatios Stamou Jr — github.com/ssjunior/0-mcp