Skip to main content

django-spec-mcp

CI PyPI Python versions Django versions Docs Coverage Ruff License

Serve django-service-specs services and selectors as a Model Context Protocol (MCP) server, conforming to MCP 2026-07-28 and 2025-11-25 (Streamable HTTP).

Coming from djangorestframework-mcp-server (drf-mcp)? Read Moving from drf-mcp before the first deploy: the settings key, the stored names and the registration calls all change.

Idea

Register kernel specs directly. The unit of registration is a ServiceSpec or a SelectorSpec from django-service-specs, not a view: the spec says what an operation takes, who may run it and what it returns, and this package serves it over MCP. The same spec can be served by any other transport on the kernel.

from dataclasses import dataclass

from django.urls import path
from django_service_specs import (
    DataclassPresenter,
    DataclassValidator,
    Parameter,
    Parameters,
    SelectorKind,
    SelectorSpec,
    ServiceSpec,
    Unrestricted,
)

from django_spec_mcp import MCPServer


@dataclass
class InvoiceInput:
    number: str
    amount_cents: int


@dataclass
class InvoiceOutput:
    id: int
    number: str
    amount_cents: int


server = MCPServer(name="my-app", auth_backend=my_auth_backend)

server.register_tool(
    ServiceSpec(
        service=create_invoice,  # def create_invoice(*, number, amount_cents)
        validator=DataclassValidator(InvoiceInput),
        presenter=DataclassPresenter(InvoiceOutput),
        permissions=[Unrestricted()],
    ),
    name="invoices.create",
    description="Create an invoice.",
)

server.register_resource(
    SelectorSpec(
        kind=SelectorKind.RETRIEVE,
        selector=get_invoice,  # def get_invoice(*, pk)
        reads=Parameters([Parameter("pk", "integer", required=True)]),
        presenter=DataclassPresenter(InvoiceOutput),
        permissions=[Unrestricted()],
    ),
    name="invoice",
    uri_template="invoices://{pk}",
)

urlpatterns = [path("mcp/", server.urls)]

See the quickstart for the full end-to-end recipe.

  • Services (mutations) and selectors (reads) → MCP tools, through register_tool; the spec's class says which kind of tool it is.
  • A RETRIEVE selector → an MCP resource, through register_resource.
  • A single /mcp endpoint speaks Streamable HTTP. The /.well-known/oauth-protected-resource endpoint comes mounted alongside.

What ships

  • Tools — tools/list, tools/call for register_tool, over a kernel ServiceSpec (mutations) or SelectorSpec (reads, with an optional FilterSet, ordering and pagination). register_tools(registry, overrides=...) registers every spec in a kernel SpecRegistry.
  • Server-supplied arguments — server_arguments=ServerArguments(values=..., withheld=...) at registration answers a declared argument for the caller: the name leaves the tool's schema, a caller's value for it is dropped and logged by name, and the binding is checked when it is registered. Route and query values a tool asks for are read from the spec's own reads.
  • Resources — resources/list, resources/templates/list, resources/read against a kernel RETRIEVE SelectorSpec, presented by its own presenter; RFC 6570 templated URIs whose variables are the spec's reads.
  • Prompts — prompts/list, prompts/get against render callables returning strings, PromptMessages, or async coroutines.
  • In-process transport surface — call tools without an HTTP round-trip: MCPServer.call_tool / acall_tool and list_tools / alist_tools drive the same dispatch and permission checks as the wire path, for embedding in agent bridges, toolsets, or management commands. unavailable_tools / aunavailable_tools name each tool the listing leaves out with the reason, so a bridge can tell its model why one is missing.
  • Tool annotations — pass annotations= at registration (or rely on the read/mutation default) to advertise MCP hints like readOnlyHint / destructiveHint on tools/list.
  • Generic _meta — pass meta= at registration to populate the base protocol's free-form _meta object on a tool, resource, or prompt's listing entry (and on the contents of resources/read). Passed through verbatim, so protocol extensions have somewhere to live.
  • Interactive views (MCP Apps) — register_ui_resource(...) declares an HTML view with typed CSP / permission metadata; ui=UIToolMeta(...) on a tool links its result to that view, and a host renders it inline in the chat. The render payload is the structuredContent you already emit, and a view's own tools/calls inherit your auth, permissions and rate limits. An extension over base MCP, so no protocol bump. We declare; the host sandboxes and renders.
  • Pluggable auth — an MCPAuthBackend verifies the bearer token; AllowAnyBackend (dev only) ships, and bearer_challenge builds the 401 challenge a backend of your own answers with. A tool or resource is guarded by its spec's own kernel permissions, and scopes= at registration adds an OAuth scope gate.
  • RFC 8707 audience binding through audience_matches, which a backend calls; RFC 9728 PRM served from the configured backend.
  • Per-binding rate limits — MCPRateLimit Protocol with FixedWindowRateLimit, SlidingWindowRateLimit, and TokenBucketRateLimit implementations shipped.
  • Async POST/DELETE + GET-side SSE push — sync urls for WSGI, async_urls for ASGI; MCPServer.notify(session_id, payload) pushes JSON-RPC frames on the session's SSE stream. Per-worker InMemorySSEBroker or cross-worker RedisSSEBroker (behind [redis]); Last-Event-ID resume via InMemorySSEReplayBuffer / RedisSSEReplayBuffer.
  • OpenTelemetry instrumentation — mcp.tools.call, mcp.resources.read, mcp.prompts.get spans (no-op without the [otel] extra installed).
  • Origin allowlist + protocol-version validation + session lifecycle per the transport rules of both revisions. 2026-07-28 and later declare version, identity and capabilities on every request and hold no session; 2025-11-25 and earlier negotiate once through initialize. Both are served concurrently on one endpoint, because a legacy client has no fall-forward mechanism.

Install

pip install django-spec-mcp                              # base install
pip install "django-spec-mcp[redis]"                     # +Redis SSE broker for multi-worker ASGI
pip install "django-spec-mcp[otel]"                      # +OpenTelemetry instrumentation
pip install "django-spec-mcp[redis,otel]"                # everything

…or with uv:

uv add django-spec-mcp                                   # base install
uv add "django-spec-mcp[redis]"                          # +Redis SSE broker for multi-worker ASGI
uv add "django-spec-mcp[otel]"                           # +OpenTelemetry instrumentation
uv add "django-spec-mcp[redis,otel]"                     # everything

Try it

Install mcp-inspector and point it at your dev server:

npx @modelcontextprotocol/inspector --url http://localhost:8000/mcp/

Inspector lists tools, fills in arguments from the generated JSON Schema, and walks the OAuth auth flow against your configured Authorization Server.

Documentation

  • Quickstart — copy-pasteable end-to-end.
  • Moving from drf-mcp — what a project on drf-mcp changes to move across.
  • Concepts — tools vs resources, sessions, tool results.
  • Authentication — backends, permissions, audience binding, bring-your-own AS recipe.
  • Recipes — focused cookbook entries.
  • Reference — autodocs for every public symbol.

License

MIT.

Metadata

Release files for django-spec-mcp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-spec-mcp 0.1.0
File Size Uploaded Provenance Actions
django_spec_mcp-0.1.0.tar.gz 913.1 kB With provenance Details for django_spec_mcp-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-spec-mcp 0.1.0
File Interpreter ABI Platform Actions
django_spec_mcp-0.1.0-py3-none-any.whl Python 3 none any Details for django_spec_mcp-0.1.0-py3-none-any.whl

Total release size: 1.3 MB

Release files / django_spec_mcp-0.1.0.tar.gz

Download URL django_spec_mcp-0.1.0.tar.gz
Size 913.1 kB
Tags Source
SHA-256 checksum
How to use checksums
7a41e68e57d0b056bf0fe442336d24374588d09ce6d2e39255070729165878a8
BLAKE2b-256 checksum
How to use checksums
930be88b4faff00dfd1756420710865e06b82dc60d05a50ef45786c7e536dc3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Release files / django_spec_mcp-0.1.0-py3-none-any.whl

Download URL django_spec_mcp-0.1.0-py3-none-any.whl
Size 393.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
73df0635a0277cf044c8034552d6ae3e60a227b42d2a43b74db92eaf10217f72
BLAKE2b-256 checksum
How to use checksums
26157f8a67e3a436d5ef172333487a56d55b42ae2e9e61defa25c41565af98fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

Security for django-spec-mcp 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_spec_mcp-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page