Dj
БесплатноНе проверенImplementing MCP in Django: Giving AI Agents Secure, Type-Safe Access to Your ORM
Описание
Implementing MCP in Django: Giving AI Agents Secure, Type-Safe Access to Your ORM
README
Implementing MCP (Model Context Protocol) in Django: giving AI agents secure, type-safe access to your ORM.
dj-mcp exposes your Django data to AI agents (Claude, custom MCP clients, etc.) over the
Model Context Protocol with tenant isolation, capability-based API keys, per-tool
auditing, and rate limiting.
Table of contents
- Architecture
- Quickstart
- Demo data + first API key
- MCP endpoints
- Available tools
- Calling the server
- Connecting an AI agent
- Management commands
- Admin UI
- Project layout
- Configuration reference
- Production notes
Architecture
┌────────────────────────────┐
AI agent │ Anthropic SDK / MCP client │
└─────────────┬──────────────┘
│ JSON-RPC over HTTP or SSE
▼
┌─────────────────────────────────────┐
│ Django (ASGI/WSGI) │
│ mcp_server/views.py │
│ - Bearer auth (sync_to_async) │
│ - rate limit (Redis/LocMem) │
├─────────────────────────────────────┤
│ mcp_server/protocol.py │
│ JSON-RPC: initialize / list / call│
├─────────────────────────────────────┤
│ mcp_server/tools.py (ToolRegistry) │
│ BaseTool + capability filter │
├─────────────────────────────────────┤
│ student_tools.py / write_tools.py │
│ lookup_student, get_student_usage,│
│ list_at_risk_students, add_note │
├─────────────────────────────────────┤
│ students/models + analytics/models │
│ Django ORM (PostgreSQL) │
└─────────────────────────────────────┘
Key properties:
- Tenant isolation is enforced by the framework, not the agent. Every tool query
is automatically scoped with
tenant_id=tenant_id. The agent cannot override it. - Capability-scoped keys. Each
MCPApiKeycarries a list of capabilities (read:students,read:analytics,update:students,create:notes,delete:data,admin). Tools are only visible to a key that has the matching capability. - Per-call audit. Every
tools/callwrites anMCPApiKeyUsagerow with status, duration, arguments, request id, and error message (if any). - Rate limited. Per-minute and per-day limits enforced by the key's
requests_per_minute/requests_per_dayfields. - Raw key never stored. Only the SHA-256 hash is persisted; the raw key is shown once at creation time.
Quickstart
Prerequisites
- Python 3.13+
- Docker (for PostgreSQL and, optionally, Redis)
- Or a local PostgreSQL + Redis if you prefer not to use Docker
1. Clone and install
git clone <your-repo-url> dj-mcp
cd dj-mcp
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install -e .
2. Configure environment
.env is already provided with sensible defaults for local development:
DJANGO_SECRET_KEY=django-insecure-...
DJANGO_DEBUG=True
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1
POSTGRES_DB=dj_mcp
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost # use "db" when running web inside docker-compose
POSTGRES_PORT=5432
DJANGO_PORT=8000
CORS_ALLOW_ALL_ORIGINS=True
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
# Optional Redis for rate limiting (defaults to LocMemCache if unset)
# DJANGO_CACHE_BACKEND=django.core.cache.backends.redis.RedisCache
# REDIS_URL=redis://127.0.0.1:6379/1
3. Start PostgreSQL
docker compose up -d db
4. Apply migrations and start the server
python manage.py migrate
python manage.py runserver 0.0.0.0:8000
5. (Optional) Run everything in Docker
docker compose up --build
This starts db (Postgres 17) and web (Django), applies migrations, and serves
on http://localhost:8000.
Demo data + first API key
A single command seeds 10 students, 30 days of usage metrics per student, sample notes, and a demo MCP API key with all non-admin capabilities:
python manage.py seed_data --tenant-id 1 --reset
Sample output:
Cleared existing data for tenant 1.
Created MCP API Key (save it - shown once):
mcp_gWPgNzYtnmNavE5m6eo6a4tq2ejZxywt1-Na_JdU0Jw
[OK] Seed complete: 10 students, 300 usage metrics, sample notes.
Save the raw key — it is never shown again. You'll pass it as
Authorization: Bearer <your-key> on every MCP request.
If you lose the key, re-run
seed_data --reset(it will clear and re-seed) or create a new key withpython manage.py create_mcp_key(see below).
MCP endpoints
All endpoints are mounted under /mcp/.
| Method | URL | Purpose |
|---|---|---|
| GET | /mcp/health/ |
Unauthenticated health check. |
| POST | /mcp/message/ |
HTTP transport — one JSON-RPC request per request. |
| GET | /mcp/sse/ |
SSE transport — opens a stream, returns session id. |
| POST | /mcp/sse/?session=<id> |
SSE transport — send JSON-RPC over a session. |
Auth
Every MCP request must include:
Authorization: Bearer mcp_<your-token>
Missing/invalid tokens return 401. Rate-limit violations return 429 with
Retry-After: 60.
JSON-RPC methods supported
| Method | Params | Description |
|---|---|---|
initialize |
none | Returns protocol version + server info. |
tools/list |
none | Lists tools the API key can call. |
tools/call |
name, arguments |
Invokes a tool; returns content blocks. |
resources/list |
none | Lists accessible resources. |
ping |
none | Health probe. |
Available tools
Each tool is a subclass of BaseTool in mcp_server/tools.py. They are
auto-registered via the @ToolRegistry.register decorator.
lookup_student — read:students
Look up a student by name or email.
{
"query": "ada",
"match_type": "partial", // or "exact"
"limit": 5 // 1..20
}
Returns: id, name, email, plan, mrr, health_score, status
(active / churned), enrollment_date.
get_student_usage — read:analytics
Aggregate API call / DAU / feature-adoption metrics for a student over N days.
{ "student_id": 1, "days": 30 }
Returns: api_calls, avg_dau, active_features.
list_at_risk_students — read:analytics
List students whose health_score is below a threshold, sorted by severity.
{
"health_score_below": 60,
"limit": 20,
"include_churned": false
}
Returns: id, name, health_score, mrr, last_active.
add_student_note — create:notes
Append a typed note to a student's record. The note is automatically flagged
created_by_agent=True and tenant-scoped.
{
"student_id": 1,
"note": "Renewal conversation went well; customer open to upgrade.",
"note_type": "opportunity" // observation | action_taken | risk_flag | opportunity | general
}
Returns: note_id, student, note_type, created: true.
Capability matrix
| Tool | Required capability | Read-only? |
|---|---|---|
lookup_student |
read:students |
yes |
get_student_usage |
read:analytics |
yes |
list_at_risk_students |
read:analytics |
yes |
add_student_note |
create:notes |
no |
The admin capability implicitly grants all of the above plus update:students
and delete:data.
Calling the server
HTTP transport (simplest)
KEY="mcp_gWPgNzYtnmNavE5m6eo6a4tq2ejZxywt1-Na_JdU0Jw"
# initialize
curl -s http://127.0.0.1:8000/mcp/message/ \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
# list tools
curl -s http://127.0.0.1:8000/mcp/message/ \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# call a tool
curl -s http://127.0.0.1:8000/mcp/message/ \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"lookup_student",
"arguments":{"query":"ada","match_type":"partial"}}}'
Sample response (tools/call):
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{"type": "text", "text": "{\"students\": [...]}"}],
"isError": false
}
}
SSE transport
# 1. Open stream in one terminal — note the session id in the X-Session-ID header
curl -N -H "Authorization: Bearer $KEY" http://127.0.0.1:8000/mcp/sse/
# 2. Send messages using the session id returned in step 1
curl -s "http://127.0.0.1:8000/mcp/sse/?session=<SESSION_ID>" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Connecting an AI agent
agent_example.py shows the canonical pattern using the Anthropic Python SDK
with the MCP client beta:
import os, anthropic
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
response = client.beta.messages.create(
model="claude-opus-4-20250514",
max_tokens=2048,
mcp_servers=[
{
"type": "url",
"url": "http://127.0.0.1:8000/mcp/sse/",
"name": "django-crm",
"api_key": os.environ["MCP_API_KEY"], # the mcp_... key from seed_data
}
],
messages=[
{"role": "user",
"content": "List students with health scores below 50 and suggest an outreach plan."}
],
betas=["mcp-client-2025-04-04"],
)
print(response.content)
Run it with:
export ANTHROPIC_API_KEY=sk-ant-...
export MCP_API_KEY=mcp_gWPgNzYtnmNavE5m6eo6a4tq2ejZxywt1-Na_JdU0Jw
python agent_example.py
The agent will:
initializeagainst your Django server,tools/listto see what's available,- call
list_at_risk_students(and possiblylookup_student/get_student_usage) to ground its answer, - produce a final response that your app can render.
Management commands
seed_data
python manage.py seed_data [--tenant-id N] [--reset]
Creates demo data and a demo API key for the given tenant. --reset clears
existing data for that tenant first.
create_mcp_key
python manage.py create_mcp_key \
--tenant-id 1 \
--name "Production Agent" \
--capabilities read:students read:analytics create:notes \
--tools lookup_student get_student_usage # optional explicit allowlist
--rate-limit 120 \
--description "Agent used in production support bot"
Prints the raw key once. Valid capability values are listed in
mcp_server/models.py::MCPCapability.
Standard commands
migrate, makemigrations, createsuperuser, runserver, shell,
dumpdata, loaddata all work as normal.
Admin UI
The Django admin is enabled at /admin/. Create a superuser:
python manage.py createsuperuser
Then log in at http://localhost:8000/admin/. Available admin pages:
- Students (
students.Student,students.StudentNote) - Analytics (
analytics.UsageMetric) - MCP / Api keys (
mcp_server.MCPApiKey) - MCP / Api key usage (
mcp_server.MCPApiKeyUsage) — fully read-only audit log of every tool call.
From the API key admin you can:
- toggle
is_active - edit capabilities (checkbox widget)
- adjust
requests_per_minute/requests_per_day - set
expires_at - inspect
last_used_at(read-only)
Project layout
dj-mcp/
├── agent_example.py # Anthropic SDK demo
├── docker-compose.yml # Postgres + Django
├── Dockerfile
├── pyproject.toml
├── manage.py
├── project/
│ ├── settings.py # INSTALLED_APPS, CACHES, REST_FRAMEWORK
│ ├── urls.py # /admin/ + /mcp/ includes
│ ├── asgi.py / wsgi.py
├── mcp_server/ # the MCP server itself
│ ├── models.py # MCPApiKey, MCPApiKeyUsage, MCPCapability
│ ├── tools.py # BaseTool, ToolRegistry, ToolResult
│ ├── protocol.py # JSON-RPC handler
│ ├── views.py # HTTP + SSE views (auth, rate limit)
│ ├── urls.py # /mcp/health/ /mcp/message/ /mcp/sse/
│ ├── admin.py
│ ├── student_tools.py # read tools
│ ├── write_tools.py # write tools
│ └── management/commands/
│ ├── create_mcp_key.py
│ └── seed_data.py
├── students/ # multi-tenant Student + StudentNote models
│ ├── models.py
│ ├── admin.py
│ └── migrations/0001_initial.py
├── analytics/ # UsageMetric model
│ ├── models.py
│ ├── admin.py
│ └── migrations/0001_initial.py
└── .env
Configuration reference
All settings are env-driven (read in project/settings.py).
| Variable | Default | Notes |
|---|---|---|
DJANGO_SECRET_KEY |
insecure fallback | Set a real key in production. |
DJANGO_DEBUG |
True |
Set False in production. |
DJANGO_ALLOWED_HOSTS |
localhost,127.0.0.1 |
Comma-separated. |
POSTGRES_DB |
dj_mcp |
|
POSTGRES_USER |
postgres |
|
POSTGRES_PASSWORD |
postgres |
|
POSTGRES_HOST |
localhost (or db in compose) |
|
POSTGRES_PORT |
5432 |
|
DJANGO_PORT |
8000 |
Used by agent_example.py. |
CORS_ALLOW_ALL_ORIGINS |
True |
Lock down in production. |
CORS_ALLOWED_ORIGINS |
http://localhost:3000,127.0.0.1:3000 |
|
DJANGO_CACHE_BACKEND |
LocMemCache |
Set to django.core.cache.backends.redis.RedisCache for production. |
REDIS_URL |
mcp-cache-default |
Redis connection string (location). |
ANTHROPIC_API_KEY |
— | Only needed by agent_example.py. |
MCP_API_KEY |
— | Only needed by agent_example.py. |
Production notes
- Use ASGI. Run behind an ASGI server (e.g.
daphne,uvicornwith--workers, orgunicorn -k uvicorn.workers.UvicornWorker) so async views and the SSE streaming endpoint perform well:pip install daphne daphne -b 0.0.0.0 -p 8000 project.asgi:application - Use Redis for caching so rate limiting is atomic and shared across workers:
Add aDJANGO_CACHE_BACKEND=django.core.cache.backends.redis.RedisCache REDIS_URL=redis://redis:6379/1redisservice todocker-compose.ymlaccordingly. - Rotate keys by setting
is_active=Falseon old keys and minting new ones viacreate_mcp_key. Old raw keys are unrecoverable — agents must be updated. - Audit. Periodically inspect
MCPApiKeyUsage(admin or DB) to find unusual call patterns, denied calls, or slow tools. - Per-tool allowlists. Use
--tools ...oncreate_mcp_keyto grant a key the principle of least privilege even within broader capability tags. - Secrets. Never commit a real
.envwith production secrets. Use a secrets manager (Azure Key Vault, AWS Secrets Manager, Doppler, etc.).
License
See LICENSE.
Установка Dj
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/azmii-ai/dj-mcpFAQ
Dj MCP бесплатный?
Да, Dj MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Dj?
Нет, Dj работает без API-ключей и переменных окружения.
Dj — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Dj в Claude Desktop, Claude Code или Cursor?
Открой Dj на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
Fetch
Web content fetching and conversion for efficient LLM usage.
AWS KB Retrieval
Retrieval from AWS Knowledge Base using Bedrock Agent Runtime.
автор: modelcontextprotocolSpring AI MCP Server
Provides auto-configuration for setting up an MCP server in Spring Boot applications.
llm-analysis-assistant
A very streamlined mcp client that supports calling and monitoring stdio/sse/streamableHttp, and can also view request responses through the /logs page. It also
автор: xuzexin-hzCompare Dj with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории ai
