Less code. Faster ships. Production-grade defaults.
Here is what you stop writing the moment you adopt 0-mcp — and what you get for free in return.
10x less code per resource
A typical Django REST resource done by hand: a list view (filters, search, ordering, pagination, serialization), a detail view, three write handlers (create, update, delete with field whitelists), session auth, rate limit, cache invalidation. That is 200–400 lines.
In 0-mcp the same resource is a class with attributes. Usually under 30 lines. Including comments.
Async by default. Always.
Every handler is async. The dispatch chain uses async Redis (redis.asyncio) and async ORM (afirst, aget, aupdate, acreate). You never have to think about sync_to_async boundaries unless you wrote blocking code on purpose. Your event loop stays free.
Redis is the engine, not an afterthought
One shared Redis client at import time. Reused for sessions, cache, rate limit, abuse blocking and security middleware. Zero per-request connection pool churn. Zero "did I close the pool" bugs.
Cache that invalidates correctly
Opt-in per resource — flip cache = True and you're done. But the part that actually matters: invalidation that doesn't blow up the world.
Cache keys live under namespaces. List responses go to list:<model>. Detail responses go to detail:<model>:<id>. When user 5 updates their profile, only their detail cache and the user list are dropped. User 7's cached detail stays warm. Your Redis stops being a stampede waiting to happen.
Security middleware that bites
SecurityMiddleware matches request paths against the patterns scanners actually use — WordPress probes, traversal, SQLi, XSS, dotfile fishing. It checks user agents against the names you'd find in any honeypot. One match and the IP is blocked for 24 hours.
A separate sliding window catches slow probers — IPs that stay quiet but rack up 4xx responses get the same 24-hour timeout.
Your logs get cleaner. Your DB stops processing junk. Your real users never notice.
Multi-tenant routing that just works
aset_tenant(account_id) switches the active database connection for the rest of the request. Combined with DBRouter, every ORM query is automatically scoped to the right tenant DB. Your model code does not change. Your business logic does not know there are multiple databases. Your queries can't accidentally cross tenants because the connection is gone.
Pydantic when you want it. Never forced.
Set create_schema, update_schema, list_schema and the library validates the request body and shapes the response through your schema. Skip those attributes and the library falls back to Django field introspection. Adopt schemas one resource at a time. No big migration.
OpenAPI that doesn't lie
You get /openapi.json (3.0.3) plus /docs rendered with Scalar — beautiful two-column layout, dark mode, search, try-it-out. Pydantic schemas are exported as JSON Schema and referenced from the spec. No manual annotations. The spec is generated from the same source of truth as the validation.
Production-grade defaults
| What you get on day one | Where it would normally live |
|---|---|
| Per-IP rate limit + abuse blocking | A custom middleware you forgot to write |
| Scanner pattern blocking | A WAF rule someone pays for |
| 4xx-flood detection | A SIEM alert someone ignores |
| Sanitized 500 responses in production | A bug where you leak stack traces |
IP spoof prevention via TRUSTED_PROXIES | A CVE waiting to happen |
| Session cookie validation against a regex | Your Redis getting probed |
| Field whitelists enforced on every write | Mass-assignment bugs |
Every feature is opt-in or opt-out at the resource level. Adopt 0-mcp for one endpoint, leave the rest of your project untouched, and grow from there. There is no rewrite.
The bottom line
Less code to write. Less code to maintain. Less code to drift. Less code that breaks. More time on the part of your product that customers actually pay for.
0-mcp by Stamatios Stamou Jr — github.com/ssjunior/0-mcp