Skip to content

Releases: MartinCastroAlvarez/django-admin-mcp-api

v1.5.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 16:39
7db4c8b

Changed

  • Bumped the django-admin-rest-api floor to ^1.7.0, which replaces the
    legacy-iframe path with server-rendered html-fragment form-spec payloads
    for ModelAdmins that render a custom template
    (#84).

Added

  • custom-template discriminator for change_form_template admins
    (#84).
    When rest-api's shared form-spec resolver renders a custom template (a
    declared change_form_template / add_form_template, or a request-driven
    change_view override) it returns renderer: "html-fragment" — opaque HTML
    an MCP client can't introspect or drive. admin.form_spec now renames that
    single upstream signal to a clear non-driveable discriminator:
    { "renderer": "custom-template", "reason": "ModelAdmin override: change_form_template", "legacy_url": …, "spa_url": …, "machine_driveable": false }. legacy_url is
    the upstream submit_url; spa_url is derived by reusing rest-api's
    map_redirect_to_spa (the /admin/SPA_URL_PREFIX swap), so detection is
    never duplicated here. admin.form_submit against such a form now refuses
    to submit — it does not fabricate field values or forward a POST — and returns
    { "ok": false, "reason": "custom-template", "message": "… not programmatically driveable …" }
    (isError: true, status 422). The pre-1.7.0 legacy-iframe branch is
    dropped: MCP clients never iframed anything, so it was never meaningful here.

Documentation

  • tools-reference.md: documented admin.form_spec / admin.form_submit
    (previously undocumented) and the custom-template discriminator + refusal.
  • api-contract.md §4.4: documented the one narrow exception to the
    pure-pass-through contract (the html-fragmentcustom-template rename).
  • threat-model.md §3: added the "agent fabricating field values for an
    opaque custom-template form" row (mitigated by the discriminator + refusal).

v1.4.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 01:18
e470cbb

Changed

  • Bumped the django-admin-rest-api floor to ^1.6.0, which adds the
    JSON 405 envelope, prepopulated/autocomplete hints, gettext i18n, and
    security logging. The MCP wire forwards rest-api's payloads unchanged, so
    no tool behaviour changes here — but pinning the floor guarantees the
    legacy-iframe discriminator (shipped in rest-api 1.5.0) is present on a
    fresh poetry install, keeping the integration suite green
    (#75).

Added

  • Defense-in-depth schema bounds on primary keys (#79).
    The shared PK string schema now carries minLength/maxLength (256) and
    a ^[^/?#]+$ pattern that forbids path-structural characters, and the pks
    arrays in admin.action / admin.bulk_update gain maxItems (1000). Typo'd
    or oversized inputs now fail with a precise INVALID_PARAMS json-pointer
    instead of forwarding to rest-api.
  • Discovery-side structured logging (#80).
    initialize, tools/list, the GET landing, and GET /manifest/ now each
    emit one {user, method, status} INFO log (mcp.method), closing the
    forensic gap where the full capability surface could be enumerated with no
    audit trail. Request bodies are still never logged.
  • initialize protocol-version negotiation (#81).
    The server now reads params.protocolVersion; a divergent value is logged
    (mcp.initialize.protocol_mismatch) and the single supported version is
    still returned, laying groundwork for future multi-version support.
  • Doc-fidelity test asserting the README "The N tools" heading equals
    len(tools.all_tools()) so the documented count can't drift again
    (#76).

Changed (internal)

  • Memoised the immutable tool catalogue (#82).
    tools_catalogue() now caches its rendered list keyed on DISABLED_TOOLS
    rather than rebuilding 18 manifest entries on every tools/list, GET /,
    and GET /manifest/. The cache is the globally-shareable base catalogue.

Documentation

  • README: corrected the "The 16 tools" heading to "The 18 tools" and
    refreshed the stale dev stats (120 tests / 95% coverage)
    (#76).
  • Static tool catalogue is now explicitly documented as not
    permission-filtered
    in api-contract.md §4.2 and threat-model.md §4.1
    (presence ≠ permission; authz is enforced per call inside rest-api). Per-user
    filtering was evaluated and intentionally declined: tools are model-generic
    verbs, the per-user model axis is already answered by admin.registry, and
    any other filter would re-derive permissions locally — forbidden by the prime
    directive (#77).
  • admin.list documented as an intentional changelist passthrough in
    tools-reference.md and the tool description: unknown keys forward verbatim
    as query params and are not schema-caught, mirroring the admin changelist
    querystring (#78).
  • Synthetic-request attribute contract promoted out of inline comments
    in dispatch.py into ARCHITECTURE.md (which attributes cross the seam,
    which are deliberately skipped, and why middleware is not re-run)
    (#82).

v1.3.0

Choose a tag to compare

@github-actions github-actions released this 01 Jun 23:05
885c9a7

Changed

  • Bumped the django-admin-rest-api floor to ^1.5.0, which broadens
    the form-spec legacy-iframe detection to request-driven custom views
    (a change_view/add_view override that renders a non-standard template,
    not just the change_form_template attribute). No MCP code changes — the
    wire adapter forwards rest-api's payload unchanged — so admin.form_spec
    now surfaces renderer: "legacy-iframe" for those views too, letting a
    caller know the form is not machine-driveable instead of inventing field
    values (#70).

Added

  • Job cross-repo fixture + end-to-end tests. The test project now
    carries the same JobAdmin fixture (request-driven custom change_view)
    and mounts the legacy admin, so an integration test asserts the MCP wire
    forwards both answers unchanged: Path A (? absent) → form-spec with the
    large-textarea metadata widget; Path B (query={"run_custom": "1"}) →
    renderer: "legacy-iframe" with the legacy URL preserved.

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 01 Jun 20:12
bfa952d

Added

  • admin.form_spec + admin.form_submit tools (#70).
    admin.form_spec(app_label, model_name, pk=None, query={}) returns the
    ModelAdmin-resolved form for a row (or the add page when pk is
    omitted) — request-aware get_form / get_fieldsets /
    get_readonly_fields, with each field's resolved widget mapped to a
    closed widget.kind enum. admin.form_submit(…, data, query={})
    re-runs is_valid() server-side through the same resolved form, so
    request-aware validation is identical across MCP, the SPA, and the
    legacy admin. Both forward through to rest-api's form-spec endpoint
    and write views, so the payload is byte-identical to the SPA's — one
    resolver, no drift.

Changed

  • Bumped the django-admin-rest-api floor to ^1.4.0, which ships
    the form-spec endpoint the two new tools forward to (#70).

Fixed

  • __version__ no longer drifts from the packaged version (#62).
    It is now derived from the installed package metadata via
    importlib.metadata.version, so manifest.server_info() (and the MCP
    initialize block) always advertise the real release version instead
    of a hand-maintained string that had fallen to 1.0.4.

Changed

  • Consolidated the Python lint stack on Ruff + mypy + bandit (#63).
    Removed Black, standalone isort, flake8, and pylint (their config
    blocks, dev dependencies, pre-commit hooks, and CI steps). Ruff now
    owns linting, formatting, and import sorting (I); the lockfile,
    scripts/lint.sh, and the docs are updated to match.
  • Enabled mypy --strict (#64). Fixed the two no-any-return
    errors at the dispatch seam (server/dispatch.py) by casting the
    resolver view callable and the synthetic RequestFactory request to
    their concrete Django types.
  • Future-proofed the dispatcher except clause (#67). Dispatcher
    exceptions now share a DispatchError base; the view catches that
    base so any new dispatcher failure mode maps to SERVER_ERROR_UPSTREAM
    instead of escaping to a Django 500.

Removed

  • Deprecated default_app_config from the package __init__ (#65).
    It was removed in Django 4.1 and this package supports Django >=4.2,
    where apps.py is auto-discovered.
  • Inert # noqa directives (A003, D401) that suppressed rules no
    configured tool enforces (#68); the explanatory text is kept as plain
    comments.

v1.1.0

Choose a tag to compare

@MartinCastroAlvarez MartinCastroAlvarez released this 31 May 11:29
28c5c1d

Added

  • Django 4.2 LTS support (django-admin-react#622).
    The pin is relaxed from django >=5.0,<7.0 to django >=4.2,<7.0;
    the CI matrix exercises 4.2 alongside 5.0 / 5.1 / 5.2 across Python
    3.10–3.13 (3.13 excluded for 4.2 conservatively since pip may
    resolve to a pre-4.2.16 release).
  • Framework :: Django :: 4.2 classifier.

Changed

  • django-admin-rest-api constraint ^1.0.11^1.1.0 to pick
    up the API package's own Django 4.2 support and its
    SimpleListFilter value-shape normalisation. Supersedes the
    ^1.0.6^1.0.11 bump from 1.0.4 — 1.1.0 is a strict
    superset.

Why a minor bump

New supported environment (Django 4.2 LTS) per SemVer's "additive
features that broaden compatibility" guideline. No behaviour change
for consumers already on 5.0+; the MCP package forwards everything
to django-admin-rest-api and adds no Django logic of its own.

v1.0.4

Choose a tag to compare

@github-actions github-actions released this 31 May 11:25
bb0de00

Changed

  • django-admin-rest-api constraint floor raised ^1.0.6^1.0.11.
    Pulls in the upstream improvements since 1.0.6: actions runner caps
    pk-list length, history view redacts a denylist of field names
    (1.0.7); PanelEndpointsMixin deprecated in favour of declaring
    panels = {...} directly on ModelAdmin (1.0.8); rest-api's own
    system checks for settings hygiene (1.0.9); N+1 perf + custom-user-
    model safety (1.0.11). URL surface is unchanged across the range;
    the MCP dispatcher forwards to the same paths.
  • admin.panel tool description updated — no longer mentions
    PanelEndpointsMixin. New copy describes the plain-Django
    panels = {"name": "method_name"} attribute approach; the mixin
    is now a deprecated no-op shim in rest-api and is kept only as a
    historical parenthetical so consumers on older rest-api versions
    recognise the term.
  • docs/tools-reference.md panel section updated to match.

Fixed

  • README serverInfo.version example bumped 1.0.2 → 1.0.3 to reflect
    the previous shipped release; test count 95 → 96 to match current.

v1.0.3

Choose a tag to compare

@github-actions github-actions released this 31 May 11:06
71baee9

The "ship the audit fixes" release. 16 audit issues triaged and closed
across six PRs. Two new public settings, one new endpoint shape, one
new URL conf, two new example directories, two new long-form docs,
plus an end-to-end Trusted-Publishing pipeline that no longer needs a
local token to ship a release.

Added

  • MAX_REQUEST_BYTES setting (default 256 KiB) — caps /mcp/
    POST envelopes well below Django's project-wide 2.5 MiB form-upload
    ceiling. Oversized requests return 413 + INVALID_REQUEST before
    the JSON parser runs.
  • DISABLED_TOOLS setting — tuple of tool names to suppress from
    tools/list and reject in tools/call. Read-only deployments
    typically set ("admin.destroy", "admin.bulk_update", "admin.set_password").
  • manage.py check integration. Three hooks: E001 (rest-api
    missing from INSTALLED_APPS), E002 (ADMIN_SITE doesn't
    resolve), W001 (typo in DISABLED_TOOLS).
  • GET /mcp/ landing. Content-negotiated — HTML for browsers,
    JSON for Accept: application/json. Shows server name, version,
    protocol, tool count, and links to the manifest.
  • django_admin_mcp_api.bundle_urls — opt-in one-include URL conf
    that auto-mounts rest-api alongside MCP under the consumer's prefix.
  • Structured logging at django_admin_mcp_api.server.views
    (mcp.auth.*, mcp.tools_call, mcp.tools_call.upstream_error).
    Bodies are never logged — only {user, tool, status}.
  • docs/tools-reference.md — one section per tool with the
    schema, the forwarded rest-api endpoint, and a worked example.
  • docs/deployment.md — WSGI / ASGI, TLS, CORS, rate-limit,
    logging, and health-check recipes.
  • examples/clients/ — drop-in Claude Desktop / Cursor / VS Code
    MCP config templates.
  • examples/headless-client/ — programmatic-login bootstrap +
    stdlib-only MCP client for scripts / CI / services.
  • README "Why two apps?" callout + the agent recipe for
    admin.action discovery + Custom AdminSite subsection.
  • Auto-create GitHub Releases on tag push. publish.yml extracts
    the CHANGELOG entry, marks pre-releases by version suffix, and
    attaches the wheel + sdist.

Changed

  • Security: _dont_enforce_csrf_checks flag no longer forwarded
    to the synthetic rest-api request. Latent CSRF-bypass risk closed.
  • Security: UnknownRestApiPath and UnsupportedDispatchMethod
    now caught
    into JSON-RPC SERVER_ERROR_UPSTREAM envelopes instead
    of bubbling to Django's 500 handler.

Notes

First release shipped end-to-end through PyPI Trusted Publishing —
no .env token, no manual poetry publish. The Trusted Publisher
was registered on PyPI for this project; the workflow's OIDC token
authenticates every future tag push.

Tests: 81 → 96 passing, 91% → 93% line coverage.

v1.0.2

Choose a tag to compare

@MartinCastroAlvarez MartinCastroAlvarez released this 31 May 10:21
e57f6e3

Changed

  • django-admin-rest-api constraint floor raised from ^1.0.0^1.0.6.
    Required to expose the new target field on action descriptors
    (batch vs detail). Fresh installs were already on 1.0.6 via the
    caret range; this just makes the requirement explicit.
  • admin.action tool description spells out the new batch/detail
    dispatch — agents reading tools/list (or admin.registry) see
    the target field on each action and can decide whether to pass
    one pk (detail) or many (batch). The wire endpoint is unchanged;
    rest-api dispatches internally based on the action callable's
    signature.
  • admin.action.pks schema description notes the per-target
    constraint (exactly 1 for detail, ≥1 for batch).

Notes

No code change in the dispatch layer. The new target field flows
through every existing tool that surfaces action descriptors
(admin.registry, admin.list, admin.retrieve) without any
wrapping — rest-api adds the field; this package forwards it. The
74 existing tests still pass; agents that already use admin.action
keep working unchanged for batch actions.

v1.0.1

Choose a tag to compare

@MartinCastroAlvarez MartinCastroAlvarez released this 31 May 10:21
0699d66

Changed

  • README rewritten in django-admin-rest-api's visual style — simple
    # H1 + blockquote tagline, six-badge row, three-package family
    table with emoji-coded rows, and single-emoji section markers
    throughout.
  • Folder READMEs (django_admin_mcp_api/, server/, tools/,
    tests/, scripts/, docs/, examples/) standardised on the
    same "tagline → In this folder → What does NOT belong here →
    See also" pattern.
  • django-admin-rest-api lockfile pinned to 1.0.1.
  • Top-level README now includes a "Configuration" section surfacing
    the DJANGO_ADMIN_MCP_API settings namespace.

Added

  • .github/workflows/publish.yml — auto-publishes to PyPI on v*
    tag push via Trusted Publishing. Records the publish as a
    deployment under the pypi environment so it shows in the GitHub
    Deployments sidebar.
  • CONTRIBUTING.md "Releases" section documenting the tag-and-push
    flow.

Removed

  • .github/README.md — GitHub was surfacing it on the repo home
    page in place of the root README.
  • ALLOW_ANONYMOUS from every user-facing doc (README, ARCHITECTURE,
    quickstart settings). The setting is now an internal test-only knob;
    the security suite scans for it leaking back into docs.

v1.0.0

Choose a tag to compare

@MartinCastroAlvarez MartinCastroAlvarez released this 31 May 10:21
81c01ff

Added

  • JSON Schema input validation on every tools/call. Arguments are
    checked against the tool's declared input_schema (Draft 2020-12)
    before forwarding to django-admin-rest-api, so malformed calls
    surface as INVALID_PARAMS with the json-pointer path of the
    failing field instead of bubbling up as a generic rest-api 400.
  • docs/threat-model.md — MCP-layer threat model (assets, trust
    boundaries, mitigations, out-of-scope items, review checklist).
  • docs/api-contract.md — the full MCP wire contract (JSON-RPC
    envelope, the three methods, error code vocabulary, semver policy).
  • GitHub issue templates (bug_report.yml, feature_request.yml,
    config.yml) and a PR template that nudge contributors toward the
    right venue and the right information.
  • .github/CODEOWNERS routing every PR review through the
    package maintainer with extra protection on the wire layer and the
    .github/ folder.

Changed

  • Pinned to django-admin-rest-api ^1.0.0 — the upstream REST API
    shipped its stable 1.0 at the same time, so the MCP adapter now
    requires the matching major. Users on the 0.1.0a0 alpha must
    upgrade to rest-api 1.x before installing this release.
  • CI matrix swaps Django via pip install instead of poetry add, so
    the Python 3.12+ × Django 6.0 cells now resolve and pass.
  • Development Status classifier promoted to 5 - Production/Stable.

Notes

This is the first stable release. The wire contract is now covered by
the semver policy in docs/api-contract.md §7 — any breaking change
will be a major version bump with a migration paragraph in this file.