django-admin-mcp-api
Exposes Django admin's ModelAdmin as MCP tools, with identical permissions, form validation, and session authentication.
README
django-admin-mcp-api
An MCP server for the Django admin — same permissions, same
ModelAdmin, no new features.
django-admin-mcp-api lets AI agents — Claude, Cursor, anything that
speaks the Model Context Protocol —
drive your Django admin. Every ModelAdmin you've already registered
on django.contrib.admin.site becomes an MCP tool, with the same
permissions, the same form validation, and the same session
auth as the HTML admin.
It is the MCP face on top of
django-admin-rest-api.
No parallel permission system. No parallel form layer. No features the
Django admin doesn't already have.
| Project | Role | PyPI |
|---|---|---|
🟦 django-admin-react |
React single-page admin frontend | django-admin-react |
🟩 django-admin-rest-api |
JSON REST API over ModelAdmin |
django-admin-rest-api |
🟪 django-admin-mcp-api (this repo) |
MCP server exposing the same API to LLMs | django-admin-mcp-api |
✨ The one design principle
This package adds no new behavior. It is an MCP wire adapter.
Every one of these is owned by your existing Django setup — not by this library:
- 🔐 Authentication — Django's session + login. The MCP endpoint
enforces the same
is_active+is_staff+AdminSite.has_permissiongate the HTML admin uses. No tokens, no custom backends, no JWTs. - 🛡️ Authorization — every tool delegates to the matching
ModelAdmin.has_view_permission/has_add_permission/has_change_permission/has_delete_permissionvia django-admin-rest-api. If your admin says no, the tool returns the upstream 403. - 📋 Field validation —
admin.create/admin.updateroute the payload through the sameModelFormDjango would render in the HTML admin, plus a JSON Schema check on the wire so malformed calls fail fast with a json-pointer path of the offending field. - ⚙️ Actions —
admin.actionruns the same action callables registered onModelAdmin.actions. Your code runs unmodified. Each action's descriptor carries atarget(batchordetail), derived by rest-api from the callable's signature: signatures ending inquerysetare batch (changelist shape), signatures ending inobj_id/pk/idare detail (single-object shape). Agents pass the right number of pks for the action's target. - 🔎 Search & filters —
admin.listusesModelAdmin.get_search_resultsandlist_filter. No parallel implementation. - 📜 Audit log — writes go through Django's
LogEntry, surfaced byadmin.historyandadmin.recent_actions. - 🌐 CSRF & sessions — Django's middleware. Nothing is
@csrf_exempt.
If a behavior isn't in the HTML admin, it isn't here. If it is in the HTML admin, this library exposes it over MCP.
🚀 Plug-and-play install
pip install django-admin-mcp-api
Two changes to your project:
# settings.py
INSTALLED_APPS = [
# ... your existing apps ...
"django.contrib.admin",
"django_admin_rest_api", # ← the REST surface (mandatory)
"django_admin_mcp_api", # ← the MCP adapter
]
# urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("django_admin_rest_api.urls")), # REST
path("mcp/", include("django_admin_mcp_api.urls")), # MCP
]
That's it. Your admin now answers JSON-RPC at POST /mcp/, with the
same session cookie and CSRF token your HTML admin already uses.
📡 The 16 tools
Each MCP tool is a 1:1 mirror of a django-admin-rest-api endpoint —
that's the whole design.
| MCP tool | What it does | rest-api endpoint |
|---|---|---|
admin.registry |
List every model the user can see | GET /api/v1/registry/ |
admin.schema |
Full admin metadata schema | GET /api/v1/schema/ |
admin.recent_actions |
The user's own LogEntry feed |
GET /api/v1/recent-actions/ |
admin.list |
A page of list-view results | GET /api/v1/<app>/<model>/ |
admin.retrieve |
A single object's detail view | GET /api/v1/<app>/<model>/<pk>/ |
admin.add_form |
Create-page field descriptors | GET /api/v1/<app>/<model>/add/ |
admin.create |
Create one object | POST /api/v1/<app>/<model>/ |
admin.update |
Partial-update one object | PATCH /api/v1/<app>/<model>/<pk>/ |
admin.destroy |
Delete one object | DELETE /api/v1/<app>/<model>/<pk>/ |
admin.bulk_update |
Apply the same patch to many objects | PATCH /api/v1/<app>/<model>/bulk/ |
admin.autocomplete |
Autocomplete a related model | GET /api/v1/<app>/<model>/autocomplete/ |
admin.action |
Run a ModelAdmin.actions action (batch or detail) |
POST /api/v1/<app>/<model>/actions/<name>/ |
admin.history |
One object's LogEntry timeline |
GET /api/v1/<app>/<model>/<pk>/history/ |
admin.delete_preview |
Cascade preview before a destroy | GET /api/v1/<app>/<model>/<pk>/delete-preview/ |
admin.set_password |
Set/change a user-like password | POST /api/v1/<app>/<model>/<pk>/password/ |
admin.panel |
A custom panel registered on the ModelAdmin |
GET /api/v1/<app>/<model>/<pk>/panel/<name>/ |
Two endpoints expose them — both gated by the same auth your admin already has:
POST /mcp/— the MCP JSON-RPC 2.0 entry point. Speaksinitialize,tools/list,tools/call. Full wire spec indocs/api-contract.md.GET /mcp/manifest/— a read-only catalogue (server info + every tool's name, description, JSON Schema) for humans and dashboards.
📸 See it run
Captured against the examples/quickstart/
demo — fresh pip install, runserver, python smoke.py. No mocks.
// POST /mcp/ method=initialize
{
"jsonrpc": "2.0", "id": 1,
"result": {
"protocolVersion": "2024-11-05",
"serverInfo": { "name": "django-admin", "version": "1.0.2" },
"capabilities": { "tools": { "listChanged": false } }
}
}
// POST /mcp/ method=tools/call name=admin.registry
{
"jsonrpc": "2.0", "id": 1,
"result": {
"content": [{ "type": "json", "json": {
"user": { "id": 1, "username": "admin", "is_staff": true },
"apps": [
{ "app_label": "auth",
"models": [
{ "model_name": "group",
"permissions": { "view": true, "add": true, "change": true, "delete": true } },
{ "model_name": "user",
"permissions": { "view": true, "add": true, "change": true, "delete": true } }
] }
]
} }],
"isError": false,
"status": 200
}
}
The permissions block above comes straight from
ModelAdmin.has_*_permission — the MCP layer doesn't decide a thing
about authorization. That's the prime directive.
⚙️ Configuration
All settings live under a single optional dict — defaults are sane, so most projects need no entry at all.
# settings.py (all keys optional)
DJANGO_ADMIN_MCP_API = {
# MCP protocol version advertised in the `initialize` result.
"PROTOCOL_VERSION": "2024-11-05",
# The `serverInfo.name` field. Useful per-environment labelling.
"SERVER_NAME": "django-admin",
# The `serverInfo.version`. None → falls back to the package version.
"SERVER_VERSION": None,
# Dotted path to the AdminSite the package introspects.
"ADMIN_SITE": "django.contrib.admin.site",
# Dotted path to a zero-arg callable returning a Dispatcher.
# None uses the built-in RestApiDispatcher.
"DISPATCHER_FACTORY": None,
}
A copy-paste-ready block lives at the bottom of
examples/quickstart/myproject/settings.py.
🔒 Security
- The MCP endpoint is not a parallel auth surface. It refuses any caller the HTML admin would refuse, with the same gate.
- Anonymous →
401. Authenticated but non-staff →403. CSRF missing onPOST→ Django's middleware 403. - Every
tools/callis validated against the tool's JSON Schema before it reaches the database. Schema violations returnINVALID_PARAMSwith the json-pointer path of the failing field. - The dispatcher carries the caller's session / user / cookies / CSRF
state to django-admin-rest-api untouched. Per-tool permission is
enforced inside rest-api by the relevant
ModelAdmin.has_*_permission. - CSRF is enforced everywhere. No view in this package is
@csrf_exempt— a pre-commit hook and a test assert this. - No token-shaped string is permitted in the repo (gitleaks + a
pygrep hook +
tests/test_security.py).
Threat model: docs/threat-model.md. Report
a vulnerability privately
here.
🧪 Local development
git clone https://github.com/MartinCastroAlvarez/django-admin-mcp-api
cd django-admin-mcp-api
poetry install
poetry run pytest
poetry run bash scripts/lint.sh
poetry run bash scripts/audit-deps.sh
77 tests, 91% line coverage, including a real end-to-end run through
django-admin-rest-api. CI runs the same suite across Python
3.10–3.13 × Django 5.0/5.1/5.2/6.0 on every PR.
🤝 Contributing
Issues, PRs, and the roadmap are on GitHub:
- 📋 Issues
- 🗺️ Project board
- 📖
CONTRIBUTING.md— house rules - 🤖
CLAUDE.md— agent contract
The lint + security gate is the same set the upstream
django-admin-rest-api and django-admin-react repos use:
ruff, black, isort, flake8, pylint, mypy, bandit, pip-audit,
gitleaks. Every change must pass all of them before merge.
📜 License
MIT. See LICENSE.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。