Skip to main content
Glama
orco82

django-drf-mcp

django-drf-mcp

Add MCP (Model Context Protocol) to any Django REST Framework project. Auto-discovers all DRF endpoints and exposes them as MCP tools — zero boilerplate.

Features

  • Zero config — add "django_drf_mcp" to INSTALLED_APPS, include the URLs, done

  • Auto-discovery — every DRF ViewSet/APIView becomes an MCP tool automatically

  • Endpoint filtering — include or exclude specific endpoints with METHOD:PATH glob patterns

  • Multiple transports — STDIO, SSE, Streamable HTTP, or embedded Django view

  • Authentication — pass auth headers (Token, JWT, Basic, API key) to MCP tool calls via HEADERS setting

  • DRF-integrated MCP view — the /mcp/ endpoint is a DRF APIView, inheriting authentication and permissions from REST_FRAMEWORK settings

  • MCP Docs UI — interactive Swagger-style docs for your MCP tools at /mcp/docs

  • DRF Swagger UI — optional built-in Swagger UI and OpenAPI schema endpoints

  • Fully configurable — control every feature via a single DJANGO_MCP settings dict

  • Auto-configures drf-spectacular — no manual setup needed

Related MCP server: django-admin-mcp

Installation

pip install django-drf-mcp

Dependencies (installed automatically)

Quick Start

1. Add to INSTALLED_APPS

# settings.py
INSTALLED_APPS = [
    ...
    "rest_framework",
    "django_drf_mcp",
]

drf-spectacular is auto-injected — you don't need to add it yourself.

2. Include URLs

# urls.py
from django.urls import path, include

urlpatterns = [
    ...
    path("", include("django_drf_mcp.urls")),
]

That's it. The MCP endpoint is now live at /mcp/.

3. Enable MCP Docs UI (requires ASGI)

For interactive documentation of your MCP tools, replace your asgi.py:

# asgi.py
import os
import django

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django.setup()

from django_drf_mcp.asgi import get_asgi_application

application = get_asgi_application()

Run with an ASGI server:

uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000

MCP Docs will be available at /mcp/docs.

Transports

STDIO (Claude Code / Claude Desktop)

python manage.py runmcp --transport stdio

SSE

python manage.py runmcp --transport sse --host 0.0.0.0 --port 8001

Streamable HTTP

python manage.py runmcp --transport streamable-http --host 0.0.0.0 --port 8001

Embedded Django View

The MCP protocol is also served at /mcp/ as a DRF APIView — no separate process needed. Supports GET (health check) and POST (JSON-RPC). Inherits authentication and permission classes from REST_FRAMEWORK settings.

MCP Client Configuration

STDIO

{
  "mcpServers": {
    "my-app": {
      "command": "python",
      "args": ["manage.py", "runmcp", "--transport", "stdio"]
    }
  }
}

With a remote Django server:

{
  "mcpServers": {
    "my-app": {
      "command": "python",
      "args": ["manage.py", "runmcp", "--transport", "stdio", "--base-url", "https://my-app.example.com"]
    }
  }
}

Streamable HTTP — Embedded (same port as Django)

The /mcp/ Django view serves MCP on the same port as your app (e.g. 8000):

{
  "mcpServers": {
    "my-app": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp/"
    }
  }
}

With authentication:

{
  "mcpServers": {
    "my-app": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp/",
      "headers": {
        "Authorization": "Token abc123..."
      }
    }
  }
}

Streamable HTTP — Standalone (separate port)

runmcp --transport streamable-http starts a standalone FastMCP server (e.g. port 8001) that proxies tool calls to Django on port 8000:

{
  "mcpServers": {
    "my-app": {
      "type": "streamable-http",
      "url": "http://localhost:8001/mcp"
    }
  }
}

With authentication:

{
  "mcpServers": {
    "my-app": {
      "type": "streamable-http",
      "url": "http://localhost:8001/mcp",
      "headers": {
        "Authorization": "Token abc123..."
      }
    }
  }
}

SSE — Standalone (separate port)

runmcp --transport sse starts a standalone FastMCP server (e.g. port 8001) that proxies tool calls to Django on port 8000:

{
  "mcpServers": {
    "my-app": {
      "type": "sse",
      "url": "http://localhost:8001/sse"
    }
  }
}

With authentication:

{
  "mcpServers": {
    "my-app": {
      "type": "sse",
      "url": "http://localhost:8001/sse",
      "headers": {
        "Authorization": "Token abc123..."
      }
    }
  }
}

Note: The client headers authenticate the MCP client to the MCP endpoint. The server-side DJANGO_MCP["HEADERS"] setting (see Authentication) authenticates MCP tool calls to the Django API. When using DRF authentication, configure both for full security.

Settings

All configuration is optional. Add a DJANGO_MCP dict to your settings.py:

DJANGO_MCP = {
    # --- Server ---
    "NAME": "django-drf-mcp",              # MCP server name
    "BASE_URL": "http://localhost:8000",    # Django server URL
    "MCP_PATH": "/mcp/",                   # MCP endpoint path

    # --- Endpoint Filtering ---
    "INCLUDE": [],                          # Only expose matching METHOD:PATH patterns
    "EXCLUDE": [],                          # Remove matching METHOD:PATH patterns

    # --- Authentication ---
    "HEADERS": {},                          # HTTP headers sent with every MCP tool call
    "INTERNAL_TOKEN": "",                   # Shared secret for MCP internal requests (optional)

    # --- MCP Docs UI ---
    "MCP_DOCS_ENABLED": True,              # Enable/disable /mcp/docs
    "MCP_DOCS_TITLE": None,                # Docs page title (defaults to NAME)
    "MCP_DOCS_DESCRIPTION": None,          # Docs description (defaults to OpenAPI description)
    "MCP_DOCS_VERSION": None,              # Docs version (defaults to OpenAPI version)
    "MCP_DOCS_EMOJI": None,                # Emoji shown before the title
    "MCP_DOCS_LINKS": [],                  # Extra links: [{"text": "...", "url": "..."}]
    "MCP_DOCS_ENABLE_CORS": True,          # Enable CORS on docs routes
    "MCP_DOCS_VERBOSE": True,              # Show tools load during server startup

    # --- DRF Swagger / Schema ---
    "SWAGGER_ENABLED": False,              # Enable Swagger UI + OpenAPI schema endpoints
    "SCHEMA_PATH": "/api/schema/",         # Schema endpoint path
    "SWAGGER_PATH": "/api/docs/",          # Swagger UI path
}

Settings Reference

Setting

Type

Default

Description

NAME

str

"django-drf-mcp"

MCP server name, shown in health check and docs

BASE_URL

str

"http://localhost:8000"

URL of the running Django server. Used as the base URL for proxying MCP tool calls and injected into the OpenAPI schema servers list

MCP_PATH

str

"/mcp/"

Path where the MCP endpoint is mounted

INCLUDE

list

[]

Only expose endpoints matching these METHOD:PATH glob patterns. Empty = include all

EXCLUDE

list

[]

Remove endpoints matching these METHOD:PATH glob patterns. Applied after INCLUDE

HEADERS

dict

{}

HTTP headers sent with every MCP tool call (e.g. {"Authorization": "Token ..."})

INTERNAL_TOKEN

str

""

Shared secret for MCP internal requests. If empty, a per-process auto-generated token is used. Set this for multi-worker or standalone runmcp deployments

MCP_DOCS_ENABLED

bool

True

Enable the MCP Docs UI (Starlette-based, requires ASGI)

MCP_DOCS_TITLE

str|None

None

Docs page title. Falls back to NAME

MCP_DOCS_DESCRIPTION

str|None

None

Docs description. Falls back to the OpenAPI schema description

MCP_DOCS_VERSION

str|None

None

Docs version string. Falls back to the OpenAPI schema version

MCP_DOCS_EMOJI

str|None

None

Emoji displayed before the docs title

MCP_DOCS_LINKS

list

[]

Extra links shown in docs. Each item: {"text": "...", "url": "..."}

MCP_DOCS_ENABLE_CORS

bool

True

Enable CORS on the MCP Docs routes

MCP_DOCS_VERBOSE

bool

True

Show tools load during server startup

SWAGGER_ENABLED

bool

False

Enable the DRF Swagger UI and OpenAPI schema endpoints

SCHEMA_PATH

str

"/api/schema/"

Path for the OpenAPI schema endpoint

SWAGGER_PATH

str

"/api/docs/"

Path for the Swagger UI endpoint

Example: Full Configuration

DJANGO_MCP = {
    "NAME": "products-api",
    "BASE_URL": "http://localhost:8000",
    "MCP_PATH": "/mcp/",
    "HEADERS": {
        "Authorization": "Token abc123...",
    },
    "MCP_DOCS_ENABLED": True,
    "MCP_DOCS_TITLE": "Products MCP Tools",
    "MCP_DOCS_DESCRIPTION": "MCP tools for the Products API",
    "MCP_DOCS_EMOJI": "\U0001f6d2",
    "MCP_DOCS_LINKS": [
        {"text": "Admin", "url": "/admin/"},
        {"text": "GitHub", "url": "https://github.com/myorg/myrepo"},
    ],
    "MCP_DOCS_ENABLE_CORS": True,
    "MCP_DOCS_VERBOSE": False,
    "SWAGGER_ENABLED": True,
}

Example: Minimal (disable docs)

DJANGO_MCP = {
    "NAME": "my-api",
    "BASE_URL": "https://my-api.example.com",
    "MCP_DOCS_ENABLED": False,
}

Endpoint Filtering

Control which DRF endpoints are exposed as MCP tools using INCLUDE and EXCLUDE patterns.

Patterns use the format "METHOD:PATH" with glob-style wildcards (*):

# Only expose GET endpoints under /api/
DJANGO_MCP = {
    "INCLUDE": ["GET:/api/*"],
}

# Expose everything except DELETE operations
DJANGO_MCP = {
    "EXCLUDE": ["DELETE:*"],
}

# Expose /api/ endpoints, but exclude DELETE on users
DJANGO_MCP = {
    "INCLUDE": ["*:/api/*"],
    "EXCLUDE": ["DELETE:/api/users/*"],
}
  • METHOD — HTTP method (GET, POST, PUT, PATCH, DELETE) or * for any method

  • PATH — URL path with * wildcard (e.g. /api/*, /api/users/{id}/)

  • Method matching is case-insensitive

  • If INCLUDE is empty (default), all endpoints are included

  • If EXCLUDE is empty (default), nothing is excluded

  • When both are set, INCLUDE is applied first, then EXCLUDE removes from the result

Authentication

If your DRF endpoints require authentication, there are two layers to configure:

1. Server-side: MCP tool calls to the Django API

Configure the HEADERS setting so MCP tool HTTP calls include credentials:

# DRF TokenAuthentication
DJANGO_MCP = {
    "HEADERS": {
        "Authorization": "Token abc123...",
    },
}

# JWT (e.g. SimpleJWT)
DJANGO_MCP = {
    "HEADERS": {
        "Authorization": "Bearer eyJ...",
    },
}

# Basic Auth
DJANGO_MCP = {
    "HEADERS": {
        "Authorization": "Basic dXNlcjpwYXNz",
    },
}

# Custom API key header
DJANGO_MCP = {
    "HEADERS": {
        "X-API-Key": "my-secret-key",
    },
}

These headers are passed to the underlying httpx.AsyncClient and included in every HTTP request made by MCP tools to your Django API.

SessionAuthentication & MCP Internal Requests

SessionAuthentication uses cookies and CSRF tokens — neither of which the MCP internal proxy has. If your views use SessionAuthentication, MCP tool calls will get 403 Forbidden.

django-drf-mcp solves this with a built-in shared secret. The library automatically generates a per-process cryptographic token and injects it into every internal MCP proxy request via the X-MCP-Internal-Token header.

To use this feature, you must add the IsMCPInternalRequest permission class to any view you want MCP tools to access. Without it, the token header is ignored and normal authentication applies.

Add it to your views using the | (OR) operator:

from rest_framework.permissions import IsAuthenticated
from django_drf_mcp.permissions import IsMCPInternalRequest

class MyViewSet(viewsets.ModelViewSet):
    permission_classes = [IsAuthenticated | IsMCPInternalRequest]

This means:

  • Browser users — must be authenticated via session (or any other auth method)

  • MCP tool calls — bypass session auth via the auto-injected secret token

The token is 256-bit cryptographically random and regenerated on every server restart. External clients cannot guess it.

Multi-worker & standalone runmcp deployments

The auto-generated token is per-process. If the MCP proxy and your DRF views run in different processes (e.g., runmcp standalone mode, or gunicorn with multiple workers behind a load balancer), set a shared INTERNAL_TOKEN:

DJANGO_MCP = {
    "INTERNAL_TOKEN": "your-shared-secret-here",  # Use a strong random value
}

When INTERNAL_TOKEN is set, it is used instead of the auto-generated per-process token. All workers and the runmcp process must share the same value.

Tip: Generate a strong token with python -c "import secrets; print(secrets.token_urlsafe(32))".

2. Client-side: MCP client to the /mcp/ endpoint

The embedded /mcp/ view is a DRF APIView and inherits DEFAULT_AUTHENTICATION_CLASSES and DEFAULT_PERMISSION_CLASSES from REST_FRAMEWORK settings. If your DRF config requires authentication globally, MCP clients must also send auth headers:

{
  "mcpServers": {
    "my-app": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp/",
      "headers": {
        "Authorization": "Token abc123..."
      }
    }
  }
}

Full authentication example

# settings.py
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.TokenAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticated",
    ],
}

DJANGO_MCP = {
    "NAME": "my-api",
    "HEADERS": {
        "Authorization": "Token abc123...",
    },
}
// .mcp.json (MCP client)
{
  "mcpServers": {
    "my-api": {
      "type": "streamable-http",
      "url": "http://localhost:8000/mcp/",
      "headers": {
        "Authorization": "Token abc123..."
      }
    }
  }
}

Endpoints

Path

Description

Controlled by

/mcp/

MCP protocol endpoint (JSON-RPC)

MCP_PATH

/mcp/docs

MCP Docs UI

MCP_DOCS_ENABLED

/mcp/openapi.json

MCP OpenAPI schema

MCP_DOCS_ENABLED

/mcp/api/tools

MCP tools JSON API (list)

MCP_DOCS_ENABLED

/mcp/api/tools/{tool_name}

MCP tool detail JSON API

MCP_DOCS_ENABLED

/mcp/favicon

MCP Docs favicon

MCP_DOCS_ENABLED

/api/schema/

DRF OpenAPI schema (YAML)

SWAGGER_ENABLED

/api/docs/

DRF Swagger UI

SWAGGER_ENABLED

How It Works

  1. django_drf_mcp auto-injects drf-spectacular into INSTALLED_APPS and configures DEFAULT_SCHEMA_CLASS

  2. On startup, it generates an OpenAPI schema from all registered DRF views

  3. The base URL is injected into the OpenAPI schema servers list

  4. FastMCP converts each API endpoint into an MCP tool via OpenAPIProvider

  5. An httpx.AsyncClient is created with the configured BASE_URL and HEADERS for proxying tool calls

  6. Tools are served via STDIO, SSE, Streamable HTTP, or the embedded Django view

  7. When running under ASGI, fastmcp-docs provides interactive documentation at /mcp/docs

Management Command

python manage.py runmcp [options]

Option

Default

Description

--transport

stdio

Transport type: stdio, sse, streamable-http

--host

0.0.0.0

Bind host (for sse / streamable-http)

--port

8001

Bind port (for sse / streamable-http)

--base-url

from settings

Override BASE_URL for proxying API calls

Requirements

  • Python >= 3.10

  • Django >= 4.0

  • Django REST Framework

A
license - permissive license
-
quality - not tested
D
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orco82/django-drf-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server