django-admin-mcp-api 0.1.0a0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. django_admin_mcp_api-0.1.0a0/LICENSE +21 -0
  2. django_admin_mcp_api-0.1.0a0/PKG-INFO +281 -0
  3. django_admin_mcp_api-0.1.0a0/README.md +248 -0
  4. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/README.md +30 -0
  5. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/__init__.py +22 -0
  6. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/apps.py +30 -0
  7. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/conf.py +57 -0
  8. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/README.md +33 -0
  9. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/__init__.py +17 -0
  10. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/dispatch.py +223 -0
  11. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/errors.py +41 -0
  12. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/jsonrpc.py +98 -0
  13. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/manifest.py +51 -0
  14. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/server/views.py +193 -0
  15. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/README.md +45 -0
  16. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/__init__.py +71 -0
  17. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/action.py +53 -0
  18. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/add_form.py +37 -0
  19. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/autocomplete.py +42 -0
  20. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/base.py +65 -0
  21. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/bulk_update.py +47 -0
  22. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/create.py +44 -0
  23. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/delete_preview.py +42 -0
  24. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/destroy.py +38 -0
  25. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/history.py +38 -0
  26. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/list_objects.py +48 -0
  27. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/panel.py +47 -0
  28. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/recent_actions.py +28 -0
  29. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/registry.py +28 -0
  30. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/retrieve.py +39 -0
  31. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/schema.py +28 -0
  32. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/set_password.py +50 -0
  33. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/tools/update.py +44 -0
  34. django_admin_mcp_api-0.1.0a0/django_admin_mcp_api/urls.py +35 -0
  35. django_admin_mcp_api-0.1.0a0/pyproject.toml +222 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 django-admin-mcp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,281 @@
1
+ Metadata-Version: 2.3
2
+ Name: django-admin-mcp-api
3
+ Version: 0.1.0a0
4
+ Summary: MCP (Model Context Protocol) adapter for django-admin-rest-api. A wire-protocol-only layer that lets agents reach the existing REST API — no new functionality, permissions, or validation.
5
+ License: MIT
6
+ Keywords: django,admin,mcp,model-context-protocol,ai,llm
7
+ Author: django-admin-mcp contributors
8
+ Requires-Python: >=3.10,<4.0
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Environment :: Web Environment
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 5.0
13
+ Classifier: Framework :: Django :: 5.1
14
+ Classifier: Framework :: Django :: 5.2
15
+ Classifier: Framework :: Django :: 6.0
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Requires-Dist: django (>=5.0,<7.0)
27
+ Requires-Dist: django-admin-rest-api (>=0.1.0a0)
28
+ Project-URL: Documentation, https://github.com/MartinCastroAlvarez/django-admin-mcp#readme
29
+ Project-URL: Homepage, https://github.com/MartinCastroAlvarez/django-admin-mcp
30
+ Project-URL: Repository, https://github.com/MartinCastroAlvarez/django-admin-mcp
31
+ Description-Content-Type: text/markdown
32
+
33
+ # django-admin-mcp-api
34
+
35
+ [![PyPI version](https://img.shields.io/pypi/v/django-admin-mcp-api.svg)](https://pypi.org/project/django-admin-mcp-api/)
36
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-admin-mcp-api.svg)](https://pypi.org/project/django-admin-mcp-api/)
37
+ [![Django versions](https://img.shields.io/badge/django-5.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-blue.svg)](https://pypi.org/project/django-admin-mcp-api/)
38
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
39
+ [![CI](https://github.com/MartinCastroAlvarez/django-admin-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MartinCastroAlvarez/django-admin-mcp/actions/workflows/ci.yml)
40
+
41
+ > **An MCP (Model Context Protocol) adapter for the Django admin.**
42
+ > Lets AI agents reach every operation of your `ModelAdmin` — list, retrieve,
43
+ > create, update, delete, run admin actions, autocomplete — through the
44
+ > standard MCP wire protocol, with the **same** authentication, permissions,
45
+ > and validation as the rest of your admin.
46
+
47
+ `django-admin-mcp-api` is a thin **wire-protocol adapter** sitting on top of
48
+ [`django-admin-rest-api`](https://github.com/MartinCastroAlvarez/django-admin-rest-api).
49
+ It introduces **no new functionality, no parallel permission system, no extra
50
+ validation, and no new business logic** — it is the MCP face on the REST API
51
+ your admin already speaks.
52
+
53
+ ---
54
+
55
+ ## The three-repo family
56
+
57
+ `django-admin-mcp-api` is one of three sibling packages that share the same
58
+ admin core. Each one exposes the same surface in a different protocol:
59
+
60
+ | Repo | Protocol | PyPI | Status |
61
+ | ------------------------------------------------------------------------------------- | ---------------- | --------------------------------------------------------- | --------------------- |
62
+ | [`django-admin-react`](https://github.com/MartinCastroAlvarez/django-admin-react) | React SPA over HTTP/JSON | [`django-admin-react`](https://pypi.org/project/django-admin-react/) | Published |
63
+ | [`django-admin-rest-api`](https://github.com/MartinCastroAlvarez/django-admin-rest-api) | HTTP REST/JSON | _to be published_ | Extraction in progress |
64
+ | **`django-admin-mcp`** (this repo) | **MCP (JSON-RPC)** | [`django-admin-mcp-api`](https://pypi.org/project/django-admin-mcp-api/) | Pre-alpha (this is the v0) |
65
+
66
+ All three reuse your existing `ModelAdmin` as the **only** source of truth
67
+ for querysets, permissions, forms, and serialization.
68
+
69
+ ---
70
+
71
+ ## Why this exists
72
+
73
+ LLM agents speak the [Model Context Protocol](https://modelcontextprotocol.io)
74
+ natively. Today they cannot reach a Django admin without a custom integration
75
+ per project. `django-admin-mcp-api` gives them a standard MCP endpoint that
76
+ exposes every admin endpoint as a tool — `admin.list`, `admin.retrieve`,
77
+ `admin.create`, `admin.update`, `admin.destroy`, `admin.action`,
78
+ `admin.autocomplete`, `admin.history`, and ten more — using the same
79
+ authentication mechanism, permissions, validation, and serialization that the
80
+ REST API and the React admin already use.
81
+
82
+ What this package is **not**:
83
+
84
+ - ❌ A new permission system.
85
+ - ❌ A new ORM layer.
86
+ - ❌ A bypass for CSRF or session auth.
87
+ - ❌ An owner of any admin behaviour.
88
+
89
+ If a behaviour is not in `django-admin-rest-api`, it is not in
90
+ `django-admin-mcp-api`. Period.
91
+
92
+ ---
93
+
94
+ ## Install (plug-and-play)
95
+
96
+ ```bash
97
+ pip install django-admin-mcp-api
98
+ ```
99
+
100
+ In `settings.py`:
101
+
102
+ ```python
103
+ INSTALLED_APPS = [
104
+ # ...your apps...
105
+ "django.contrib.admin",
106
+ "django_admin_rest_api", # the REST layer (mandatory at v0.1+)
107
+ "django_admin_mcp_api", # the MCP adapter
108
+ ]
109
+ ```
110
+
111
+ In your root `urls.py`:
112
+
113
+ ```python
114
+ from django.urls import include, path
115
+
116
+ urlpatterns = [
117
+ path("admin/", admin.site.urls),
118
+ path("api/v1/", include("django_admin_rest_api.urls")), # REST
119
+ path("mcp/", include("django_admin_mcp_api.urls")), # MCP (this package)
120
+ ]
121
+ ```
122
+
123
+ That is the entire integration. There is nothing else to configure.
124
+
125
+ ---
126
+
127
+ ## What you get
128
+
129
+ Two endpoints, both gated by the **same** auth your admin already has
130
+ (Django session + CSRF + `AdminSite.has_permission`):
131
+
132
+ - `POST /mcp/` — the MCP JSON-RPC 2.0 entry point. Speaks `initialize`,
133
+ `tools/list`, and `tools/call`.
134
+ - `GET /mcp/manifest/` — a read-only catalogue (server info + every tool's
135
+ name, description, JSON-Schema) for humans and dashboards.
136
+
137
+ ### The tool catalogue
138
+
139
+ | MCP tool | What it does | rest-api endpoint |
140
+ | ----------------------- | --------------------------------------------------------------------- | ------------------------------------------------------- |
141
+ | `admin.registry` | List every model the user can see | `GET /api/v1/registry/` |
142
+ | `admin.schema` | The full admin metadata schema | `GET /api/v1/schema/` |
143
+ | `admin.recent_actions` | The user's own LogEntry feed | `GET /api/v1/recent-actions/` |
144
+ | `admin.list` | A page of list-view results | `GET /api/v1/<app>/<model>/` |
145
+ | `admin.retrieve` | A single object's detail view | `GET /api/v1/<app>/<model>/<pk>/` |
146
+ | `admin.add_form` | Create-page field descriptors | `GET /api/v1/<app>/<model>/add/` |
147
+ | `admin.create` | Create one object | `POST /api/v1/<app>/<model>/` |
148
+ | `admin.update` | Partial-update one object | `PATCH /api/v1/<app>/<model>/<pk>/` |
149
+ | `admin.destroy` | Delete one object | `DELETE /api/v1/<app>/<model>/<pk>/` |
150
+ | `admin.bulk_update` | Apply the same patch to many objects | `PATCH /api/v1/<app>/<model>/bulk/` |
151
+ | `admin.autocomplete` | Autocomplete a related model | `GET /api/v1/<app>/<model>/autocomplete/` |
152
+ | `admin.action` | Run a `ModelAdmin.actions` action | `POST /api/v1/<app>/<model>/actions/<name>/` |
153
+ | `admin.history` | One object's LogEntry timeline | `GET /api/v1/<app>/<model>/<pk>/history/` |
154
+ | `admin.delete_preview` | Cascade preview before a destroy | `GET /api/v1/<app>/<model>/<pk>/delete-preview/` |
155
+ | `admin.set_password` | Set/change a user-like password | `POST /api/v1/<app>/<model>/<pk>/password/` |
156
+ | `admin.panel` | A custom panel registered on the ModelAdmin | `GET /api/v1/<app>/<model>/<pk>/panel/<name>/` |
157
+
158
+ Every tool is a 1:1 mirror of a `django-admin-rest-api` endpoint.
159
+
160
+ ---
161
+
162
+ ## Quick tour
163
+
164
+ ### Discover the catalogue
165
+
166
+ ```console
167
+ $ curl -s http://localhost:8000/mcp/manifest/ \
168
+ --cookie "sessionid=…" | jq '.tools[].name'
169
+ "admin.registry"
170
+ "admin.schema"
171
+ "admin.recent_actions"
172
+ "admin.list"
173
+ ...
174
+ ```
175
+
176
+ ### Initialize an MCP session
177
+
178
+ ```console
179
+ $ curl -s http://localhost:8000/mcp/ \
180
+ -H "Content-Type: application/json" \
181
+ -H "X-CSRFToken: $(grep csrftoken ~/.cookies)" \
182
+ --cookie "sessionid=…" \
183
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | jq .
184
+ {
185
+ "jsonrpc": "2.0",
186
+ "id": 1,
187
+ "result": {
188
+ "protocolVersion": "2024-11-05",
189
+ "serverInfo": { "name": "django-admin", "version": "0.1.0" },
190
+ "capabilities": { "tools": { "listChanged": false } }
191
+ }
192
+ }
193
+ ```
194
+
195
+ ### Call a tool
196
+
197
+ ```console
198
+ $ curl -s http://localhost:8000/mcp/ \
199
+ -H "Content-Type: application/json" -H "X-CSRFToken: …" \
200
+ --cookie "sessionid=…" \
201
+ -d '{
202
+ "jsonrpc": "2.0",
203
+ "id": 2,
204
+ "method": "tools/call",
205
+ "params": {
206
+ "name": "admin.list",
207
+ "arguments": {"app_label": "auth", "model_name": "user", "page": 1}
208
+ }
209
+ }' | jq .
210
+ ```
211
+
212
+ The response is the rest-api response, wrapped in an MCP `content` envelope.
213
+
214
+ ---
215
+
216
+ ## Screenshots
217
+
218
+ > Screenshots are generated by `scripts/screenshots.sh` against a local
219
+ > Django dev server. They will be regenerated and committed when
220
+ > `django-admin-rest-api` ships and the dispatcher is wired through.
221
+
222
+ - `docs/screenshots/manifest-curl.png` — `GET /mcp/manifest/` rendered
223
+ - `docs/screenshots/tools-list.png` — `tools/list` from Claude Desktop
224
+ - `docs/screenshots/agent-driving-admin.png` — an agent picking and
225
+ running an admin action via `admin.action`
226
+
227
+ (Placeholder until the dispatcher is live — tracked in [#3](https://github.com/MartinCastroAlvarez/django-admin-mcp/issues).)
228
+
229
+ ---
230
+
231
+ ## Security
232
+
233
+ Defaults are deliberately strict and match the rest of the family:
234
+
235
+ - **Staff-only.** Anonymous requests get `401`, non-staff get `403`. The
236
+ staff gate is the *minimum* — the real permission check happens inside
237
+ `django-admin-rest-api` per tool.
238
+ - **CSRF always on.** No view in this package is `@csrf_exempt`. The
239
+ pre-commit hook fails any PR that introduces one.
240
+ - **No new permission code.** This package never calls `user.has_perm` or
241
+ `objects.all()` — those checks belong to rest-api.
242
+ - **No secrets in code or commits.** `gitleaks` + a pygrep hook block any
243
+ token-shaped string from reaching the index.
244
+
245
+ See [SECURITY.md](SECURITY.md) for the full set of invariants and how to
246
+ report a vulnerability.
247
+
248
+ ---
249
+
250
+ ## Status
251
+
252
+ | Component | Status |
253
+ | ------------------------------------------ | -------------------------------------------- |
254
+ | MCP wire protocol (initialize, tools/list, tools/call) | ✅ implemented + tested |
255
+ | 16-tool catalogue | ✅ implemented + tested |
256
+ | Default dispatcher | ⏳ placeholder until `django-admin-rest-api` is on PyPI |
257
+ | PyPI release | ⏳ blocked on `django-admin-rest-api` |
258
+
259
+ Tracked in the [GitHub project board](https://github.com/MartinCastroAlvarez/django-admin-mcp/projects).
260
+
261
+ ---
262
+
263
+ ## Contributing
264
+
265
+ See [CONTRIBUTING.md](CONTRIBUTING.md). The TL;DR:
266
+
267
+ ```bash
268
+ poetry install
269
+ poetry run pytest
270
+ poetry run bash scripts/lint.sh
271
+ ```
272
+
273
+ PRs go through review per [CLAUDE.md](CLAUDE.md). The same linters,
274
+ formatters, and security gates as `django-admin-react` run on every PR.
275
+
276
+ ---
277
+
278
+ ## License
279
+
280
+ MIT — see [LICENSE](LICENSE).
281
+
@@ -0,0 +1,248 @@
1
+ # django-admin-mcp-api
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/django-admin-mcp-api.svg)](https://pypi.org/project/django-admin-mcp-api/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-admin-mcp-api.svg)](https://pypi.org/project/django-admin-mcp-api/)
5
+ [![Django versions](https://img.shields.io/badge/django-5.0%20%7C%205.1%20%7C%205.2%20%7C%206.0-blue.svg)](https://pypi.org/project/django-admin-mcp-api/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+ [![CI](https://github.com/MartinCastroAlvarez/django-admin-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MartinCastroAlvarez/django-admin-mcp/actions/workflows/ci.yml)
8
+
9
+ > **An MCP (Model Context Protocol) adapter for the Django admin.**
10
+ > Lets AI agents reach every operation of your `ModelAdmin` — list, retrieve,
11
+ > create, update, delete, run admin actions, autocomplete — through the
12
+ > standard MCP wire protocol, with the **same** authentication, permissions,
13
+ > and validation as the rest of your admin.
14
+
15
+ `django-admin-mcp-api` is a thin **wire-protocol adapter** sitting on top of
16
+ [`django-admin-rest-api`](https://github.com/MartinCastroAlvarez/django-admin-rest-api).
17
+ It introduces **no new functionality, no parallel permission system, no extra
18
+ validation, and no new business logic** — it is the MCP face on the REST API
19
+ your admin already speaks.
20
+
21
+ ---
22
+
23
+ ## The three-repo family
24
+
25
+ `django-admin-mcp-api` is one of three sibling packages that share the same
26
+ admin core. Each one exposes the same surface in a different protocol:
27
+
28
+ | Repo | Protocol | PyPI | Status |
29
+ | ------------------------------------------------------------------------------------- | ---------------- | --------------------------------------------------------- | --------------------- |
30
+ | [`django-admin-react`](https://github.com/MartinCastroAlvarez/django-admin-react) | React SPA over HTTP/JSON | [`django-admin-react`](https://pypi.org/project/django-admin-react/) | Published |
31
+ | [`django-admin-rest-api`](https://github.com/MartinCastroAlvarez/django-admin-rest-api) | HTTP REST/JSON | _to be published_ | Extraction in progress |
32
+ | **`django-admin-mcp`** (this repo) | **MCP (JSON-RPC)** | [`django-admin-mcp-api`](https://pypi.org/project/django-admin-mcp-api/) | Pre-alpha (this is the v0) |
33
+
34
+ All three reuse your existing `ModelAdmin` as the **only** source of truth
35
+ for querysets, permissions, forms, and serialization.
36
+
37
+ ---
38
+
39
+ ## Why this exists
40
+
41
+ LLM agents speak the [Model Context Protocol](https://modelcontextprotocol.io)
42
+ natively. Today they cannot reach a Django admin without a custom integration
43
+ per project. `django-admin-mcp-api` gives them a standard MCP endpoint that
44
+ exposes every admin endpoint as a tool — `admin.list`, `admin.retrieve`,
45
+ `admin.create`, `admin.update`, `admin.destroy`, `admin.action`,
46
+ `admin.autocomplete`, `admin.history`, and ten more — using the same
47
+ authentication mechanism, permissions, validation, and serialization that the
48
+ REST API and the React admin already use.
49
+
50
+ What this package is **not**:
51
+
52
+ - ❌ A new permission system.
53
+ - ❌ A new ORM layer.
54
+ - ❌ A bypass for CSRF or session auth.
55
+ - ❌ An owner of any admin behaviour.
56
+
57
+ If a behaviour is not in `django-admin-rest-api`, it is not in
58
+ `django-admin-mcp-api`. Period.
59
+
60
+ ---
61
+
62
+ ## Install (plug-and-play)
63
+
64
+ ```bash
65
+ pip install django-admin-mcp-api
66
+ ```
67
+
68
+ In `settings.py`:
69
+
70
+ ```python
71
+ INSTALLED_APPS = [
72
+ # ...your apps...
73
+ "django.contrib.admin",
74
+ "django_admin_rest_api", # the REST layer (mandatory at v0.1+)
75
+ "django_admin_mcp_api", # the MCP adapter
76
+ ]
77
+ ```
78
+
79
+ In your root `urls.py`:
80
+
81
+ ```python
82
+ from django.urls import include, path
83
+
84
+ urlpatterns = [
85
+ path("admin/", admin.site.urls),
86
+ path("api/v1/", include("django_admin_rest_api.urls")), # REST
87
+ path("mcp/", include("django_admin_mcp_api.urls")), # MCP (this package)
88
+ ]
89
+ ```
90
+
91
+ That is the entire integration. There is nothing else to configure.
92
+
93
+ ---
94
+
95
+ ## What you get
96
+
97
+ Two endpoints, both gated by the **same** auth your admin already has
98
+ (Django session + CSRF + `AdminSite.has_permission`):
99
+
100
+ - `POST /mcp/` — the MCP JSON-RPC 2.0 entry point. Speaks `initialize`,
101
+ `tools/list`, and `tools/call`.
102
+ - `GET /mcp/manifest/` — a read-only catalogue (server info + every tool's
103
+ name, description, JSON-Schema) for humans and dashboards.
104
+
105
+ ### The tool catalogue
106
+
107
+ | MCP tool | What it does | rest-api endpoint |
108
+ | ----------------------- | --------------------------------------------------------------------- | ------------------------------------------------------- |
109
+ | `admin.registry` | List every model the user can see | `GET /api/v1/registry/` |
110
+ | `admin.schema` | The full admin metadata schema | `GET /api/v1/schema/` |
111
+ | `admin.recent_actions` | The user's own LogEntry feed | `GET /api/v1/recent-actions/` |
112
+ | `admin.list` | A page of list-view results | `GET /api/v1/<app>/<model>/` |
113
+ | `admin.retrieve` | A single object's detail view | `GET /api/v1/<app>/<model>/<pk>/` |
114
+ | `admin.add_form` | Create-page field descriptors | `GET /api/v1/<app>/<model>/add/` |
115
+ | `admin.create` | Create one object | `POST /api/v1/<app>/<model>/` |
116
+ | `admin.update` | Partial-update one object | `PATCH /api/v1/<app>/<model>/<pk>/` |
117
+ | `admin.destroy` | Delete one object | `DELETE /api/v1/<app>/<model>/<pk>/` |
118
+ | `admin.bulk_update` | Apply the same patch to many objects | `PATCH /api/v1/<app>/<model>/bulk/` |
119
+ | `admin.autocomplete` | Autocomplete a related model | `GET /api/v1/<app>/<model>/autocomplete/` |
120
+ | `admin.action` | Run a `ModelAdmin.actions` action | `POST /api/v1/<app>/<model>/actions/<name>/` |
121
+ | `admin.history` | One object's LogEntry timeline | `GET /api/v1/<app>/<model>/<pk>/history/` |
122
+ | `admin.delete_preview` | Cascade preview before a destroy | `GET /api/v1/<app>/<model>/<pk>/delete-preview/` |
123
+ | `admin.set_password` | Set/change a user-like password | `POST /api/v1/<app>/<model>/<pk>/password/` |
124
+ | `admin.panel` | A custom panel registered on the ModelAdmin | `GET /api/v1/<app>/<model>/<pk>/panel/<name>/` |
125
+
126
+ Every tool is a 1:1 mirror of a `django-admin-rest-api` endpoint.
127
+
128
+ ---
129
+
130
+ ## Quick tour
131
+
132
+ ### Discover the catalogue
133
+
134
+ ```console
135
+ $ curl -s http://localhost:8000/mcp/manifest/ \
136
+ --cookie "sessionid=…" | jq '.tools[].name'
137
+ "admin.registry"
138
+ "admin.schema"
139
+ "admin.recent_actions"
140
+ "admin.list"
141
+ ...
142
+ ```
143
+
144
+ ### Initialize an MCP session
145
+
146
+ ```console
147
+ $ curl -s http://localhost:8000/mcp/ \
148
+ -H "Content-Type: application/json" \
149
+ -H "X-CSRFToken: $(grep csrftoken ~/.cookies)" \
150
+ --cookie "sessionid=…" \
151
+ -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | jq .
152
+ {
153
+ "jsonrpc": "2.0",
154
+ "id": 1,
155
+ "result": {
156
+ "protocolVersion": "2024-11-05",
157
+ "serverInfo": { "name": "django-admin", "version": "0.1.0" },
158
+ "capabilities": { "tools": { "listChanged": false } }
159
+ }
160
+ }
161
+ ```
162
+
163
+ ### Call a tool
164
+
165
+ ```console
166
+ $ curl -s http://localhost:8000/mcp/ \
167
+ -H "Content-Type: application/json" -H "X-CSRFToken: …" \
168
+ --cookie "sessionid=…" \
169
+ -d '{
170
+ "jsonrpc": "2.0",
171
+ "id": 2,
172
+ "method": "tools/call",
173
+ "params": {
174
+ "name": "admin.list",
175
+ "arguments": {"app_label": "auth", "model_name": "user", "page": 1}
176
+ }
177
+ }' | jq .
178
+ ```
179
+
180
+ The response is the rest-api response, wrapped in an MCP `content` envelope.
181
+
182
+ ---
183
+
184
+ ## Screenshots
185
+
186
+ > Screenshots are generated by `scripts/screenshots.sh` against a local
187
+ > Django dev server. They will be regenerated and committed when
188
+ > `django-admin-rest-api` ships and the dispatcher is wired through.
189
+
190
+ - `docs/screenshots/manifest-curl.png` — `GET /mcp/manifest/` rendered
191
+ - `docs/screenshots/tools-list.png` — `tools/list` from Claude Desktop
192
+ - `docs/screenshots/agent-driving-admin.png` — an agent picking and
193
+ running an admin action via `admin.action`
194
+
195
+ (Placeholder until the dispatcher is live — tracked in [#3](https://github.com/MartinCastroAlvarez/django-admin-mcp/issues).)
196
+
197
+ ---
198
+
199
+ ## Security
200
+
201
+ Defaults are deliberately strict and match the rest of the family:
202
+
203
+ - **Staff-only.** Anonymous requests get `401`, non-staff get `403`. The
204
+ staff gate is the *minimum* — the real permission check happens inside
205
+ `django-admin-rest-api` per tool.
206
+ - **CSRF always on.** No view in this package is `@csrf_exempt`. The
207
+ pre-commit hook fails any PR that introduces one.
208
+ - **No new permission code.** This package never calls `user.has_perm` or
209
+ `objects.all()` — those checks belong to rest-api.
210
+ - **No secrets in code or commits.** `gitleaks` + a pygrep hook block any
211
+ token-shaped string from reaching the index.
212
+
213
+ See [SECURITY.md](SECURITY.md) for the full set of invariants and how to
214
+ report a vulnerability.
215
+
216
+ ---
217
+
218
+ ## Status
219
+
220
+ | Component | Status |
221
+ | ------------------------------------------ | -------------------------------------------- |
222
+ | MCP wire protocol (initialize, tools/list, tools/call) | ✅ implemented + tested |
223
+ | 16-tool catalogue | ✅ implemented + tested |
224
+ | Default dispatcher | ⏳ placeholder until `django-admin-rest-api` is on PyPI |
225
+ | PyPI release | ⏳ blocked on `django-admin-rest-api` |
226
+
227
+ Tracked in the [GitHub project board](https://github.com/MartinCastroAlvarez/django-admin-mcp/projects).
228
+
229
+ ---
230
+
231
+ ## Contributing
232
+
233
+ See [CONTRIBUTING.md](CONTRIBUTING.md). The TL;DR:
234
+
235
+ ```bash
236
+ poetry install
237
+ poetry run pytest
238
+ poetry run bash scripts/lint.sh
239
+ ```
240
+
241
+ PRs go through review per [CLAUDE.md](CLAUDE.md). The same linters,
242
+ formatters, and security gates as `django-admin-react` run on every PR.
243
+
244
+ ---
245
+
246
+ ## License
247
+
248
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,30 @@
1
+ # `django_admin_mcp_api/`
2
+
3
+ The shipped package. A Django app + an MCP wire-protocol adapter over
4
+ [`django-admin-rest-api`](https://github.com/MartinCastroAlvarez/django-admin-rest-api).
5
+
6
+ ## What lives here
7
+
8
+ | File / dir | Purpose |
9
+ | --------------------- | ------------------------------------------------------------- |
10
+ | `__init__.py` | Version + default app config pointer. |
11
+ | `apps.py` | `DjangoAdminMcpApiConfig` — registered via `INSTALLED_APPS`. |
12
+ | `conf.py` | The one place to read `DJANGO_ADMIN_MCP_API` settings from. |
13
+ | `urls.py` | Two URLs: `POST /` (MCP JSON-RPC) and `GET /manifest/`. |
14
+ | [`server/`](server/) | The wire layer (views, JSON-RPC, dispatcher, manifest). |
15
+ | [`tools/`](tools/) | One module per MCP tool (16 tools total). |
16
+
17
+ ## What must NOT live here
18
+
19
+ - Database queries.
20
+ - Permission checks (the staff gate in `server/views.py` is the only
21
+ exception, and it is a baseline — the real check is in rest-api).
22
+ - Serialization.
23
+ - Any new admin behaviour.
24
+
25
+ ## Pointers
26
+
27
+ - [`../README.md`](../README.md) — user-facing docs.
28
+ - [`../ARCHITECTURE.md`](../ARCHITECTURE.md) — request flow + dispatcher seam.
29
+ - [`../SECURITY.md`](../SECURITY.md) — security invariants.
30
+ - [`../CLAUDE.md`](../CLAUDE.md) — agent contract.
@@ -0,0 +1,22 @@
1
+ """django-admin-mcp-api: an MCP (Model Context Protocol) server for the Django admin.
2
+
3
+ The package exposes every operation of a consumer's ``ModelAdmin`` as an MCP
4
+ tool, reusing Django's session + CSRF auth and the consumer's existing
5
+ ``AdminSite`` registry. See ``ARCHITECTURE.md`` for the full design and
6
+ ``SECURITY.md`` for the non-negotiable security rules.
7
+
8
+ This is the public surface; everything else under ``server/`` and
9
+ ``tools/`` is implementation. The Django app config is auto-discovered
10
+ via ``apps.py`` once ``"django_admin_mcp_api"`` is added to
11
+ ``INSTALLED_APPS``.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ __version__ = "0.1.0a0"
17
+
18
+ # Default Django app config — consumers add ``"django_admin_mcp_api"`` to
19
+ # INSTALLED_APPS and Django picks this up automatically.
20
+ default_app_config = "django_admin_mcp_api.apps.DjangoAdminMcpApiConfig"
21
+
22
+ __all__ = ["__version__", "default_app_config"]
@@ -0,0 +1,30 @@
1
+ """Django app config for django-admin-mcp-api."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from django.apps import AppConfig
6
+
7
+
8
+ class DjangoAdminMcpApiConfig(AppConfig):
9
+ """App config for ``django_admin_mcp_api``.
10
+
11
+ Registered via ``INSTALLED_APPS``. We deliberately do not perform any
12
+ side-effects in ``ready()`` other than configuration validation —
13
+ every endpoint is opt-in through the consumer's URL conf.
14
+ """
15
+
16
+ name = "django_admin_mcp_api"
17
+ label = "django_admin_mcp_api"
18
+ verbose_name = "Django Admin MCP API"
19
+ default_auto_field = "django.db.models.BigAutoField"
20
+
21
+ def ready(self) -> None:
22
+ """Validate settings on app startup.
23
+
24
+ Kept light to avoid slow Django boot in test suites. Any future
25
+ signal wiring goes here.
26
+ """
27
+ # Importing the conf module triggers settings validation via
28
+ # ``django.core.checks``-friendly accessors. See
29
+ # ``django_admin_mcp_api.conf`` for the actual checks.
30
+ from django_admin_mcp_api import conf # noqa: F401