The Django MCP server. Even if you don't use Django.
Stop writing the same MCP server scaffolding on every project — tool registry, schema generation, transport plumbing, auth, rate limit. 0-mcp collapses it into a single class. Your Django models become agent-callable tools instantly; the REST API ships at the same time, from the same source. And if you're not on Django at all, 0-mcp init reads any MySQL or Postgres schema and writes the entire project for you in one shot.
Already have a database but no Django? Skip the boilerplate entirely:
pip install 'django-zeromcp[gen-mysql]' 0-mcp init # interactive — prompts for host/db/credentials cd ./<dbname> && ./run.sh
Every table becomes a model, every model becomes an MCP tool. ~10 seconds. Full walkthrough.
Slide 1 — The problem
Every team adopting MCP today writes the same thing:
- Hundreds of lines of tool registration boilerplate
- JSON Schema hand-built or kept manually in sync with the ORM
- Transport plumbing (stdio, HTTP) wired from scratch
- Auth and rate limit re-implemented because the MCP layer doesn't share them with the REST API
- A second codebase that drifts away from the API the agents are supposed to mirror
And then the next project starts and it's all written again.
Slide 2 — The promise
Setup (once per app)
from zeromcp import BaseResource from myapp.models import Space
Your entire resource — 2 lines
class SpaceResource(BaseResource):
model = SpaceWhat you got for free — MCP
list_space,get_space,create_space,update_space,delete_spaceas typed tools- Auto-generated JSON Schema from your Django fields
stdiotransport (Claude Desktop, Cursor) andHTTPtransport (JSON-RPC over POST, for web agents)- Tool descriptions and output shapes derived from the same Pydantic models the API uses
What you got for free — REST API
GET /spaces— paginated, filterable, searchable, sortableGET /spaces/{id}— detailPOST /spaces— createPATCH /spaces/{id}— updateDELETE /spaces/{id}— deleteGET /docs— interactive OpenAPI UIGET /openapi.json— full spec
Async dispatch, session and API-key auth, per-IP rate limit, scanner blocking, sanitized 500s — all on by default. Both for MCP and REST.
Slide 3 — The numbers
| Metric | Hand-written MCP | 0-mcp |
|---|---|---|
| Lines per resource (typical) | 300–600 | 2–30 |
| Tool schema source | hand-rolled | from Django/Pydantic |
| Transports supported | one, manually | stdio + HTTP built in |
| Auth shared with REST API | no, two codebases | yes, one source |
| Rate limit on tool calls | DIY | inherited from API layer |
| Multi-tenant scoping | DIY per tool | one config line |
| Time to first tool | hours to days | 5 minutes |
Slide 4 — Production-ready by default
| Concern | Status |
|---|---|
| MCP server (stdio + HTTP) | ✅ opt-in |
| MCP tool schema generation | ✅ default |
| Async views (Django 5+) | ✅ default |
| Redis-backed sessions / cache / rate limit | ✅ default |
| Multi-tenant DB routing | ✅ opt-in |
| Pydantic validation | ✅ opt-in |
| Scanner blocking + 4xx flood detection | ✅ default |
| OpenAPI 3.0.3 + Scalar UI | ✅ one flag |
| HMAC-SHA256 anti-replay token | ✅ opt-in |
| IP spoof prevention via TRUSTED_PROXIES | ✅ default |
| Sanitized 500 responses in production | ✅ default |
| Test suite | ✅ 165 tests, green |
Slide 5 — Cache that doesn't lie
Most cache layers blow up the world on every write. 0-mcp's doesn't.
| Operation | Effect |
|---|---|
GET /spaces | cached under list:<model> |
GET /spaces/5 | cached under detail:<model>:5 |
PATCH /spaces/5 | invalidates list:<model> + detail:<model>:5 only |
DELETE /spaces/5 | same as PATCH |
POST /spaces | invalidates list:<model> only |
Editing row 5 does not drop the cache for row 7. Your Redis stops being a stampede waiting to happen. The same invalidation rules apply to MCP tool responses — your agent never serves stale data.
Slide 6 — Security middleware that bites
SecurityMiddleware matches request paths against patterns scanners actually use:
- WordPress probes (
/wp-admin,/wp-login.php) - Dotfile fishing (
/.env,/.git,/.aws) - Traversal (
../) - SQL injection payloads in URLs
- XSS in URL params
And user agents like sqlmap, nikto, nuclei, masscan, acunetix. One match, IP blocked for 24 hours. Logs get clean. DB stops processing junk. Real users never notice. The same protection covers the MCP HTTP transport.
Slide 7 — Multi-tenant routing that disappears
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 cannot cross tenants because the connection is gone. An agent authenticated for tenant A cannot see tenant B's data — the routing applies to MCP tool calls automatically.
Slide 8 — Pydantic when you want it
class UserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=8)
class UserResource(BaseResource):
model = User
create_schema = UserCreateSet the schema, get validation. Skip it, fall back to Django field introspection. Adopt one resource at a time. No big migration. The same schemas drive MCP tool input validation and OpenAPI generation.
Slide 9 — OpenAPI that does not lie
urlpatterns = get_routes(endpoints)
Done. You now have:
GET /openapi.json— generated from your resources, references your Pydantic schemasGET /docs— Scalar UI: two-column layout, dark mode, search, try-it-out (AI assistant disabled for privacy)
Slide 10 — Who is this for
- Django teams building agents or copilots that need to read and act on app data
- Products integrating with Claude Desktop, Cursor, or any MCP client
- SaaS apps that want API + MCP from one definition, not two codebases
- Multi-tenant apps that need agent access scoped per tenant, automatically
- Teams that also want a clean REST API — that comes free
- Solo founders shipping fast
Slide 11 — When NOT to use it
Be honest about it:
- No Redis available (sessions, cache, rate limit and abuse all rely on it)
- Very custom auth (OAuth2 server, complex permission matrices)
- Endpoints that are mostly RPC, not CRUD — and you don't want them as MCP tools either
- You don't have Django models — 0-mcp wraps your ORM, not arbitrary code
- You want a huge plugin ecosystem — 0-mcp is small on purpose
Slide 12 — Get started
pip install django-zeromcp # MCP server is bundled in the base install — no extras needed. pip install 'django-zeromcp[schemas]' # optional Pydantic
- Connect to Claude Desktop in 5 minutes — see the MCP guide
- Or just use the REST API — see the quickstart
- GitHub — https://github.com/ssjunior/0-mcp
- License — MIT
- Author — Stamatios Stamou Jr
Slide 13 — One-liner
Ship an MCP server in 2 lines. Not 300. The first tool takes five minutes. The fiftieth takes five minutes too. API ships in the same line.
0-mcp by Stamatios Stamou Jr — github.com/ssjunior/0-mcp