Skip to main content
Glama
edelvalle

django-admin-fastmcp

by edelvalle

django-admin-fastmcp

Многоразовое Django-приложение, которое предоставляет админку Django как MCP-сервер, построенный на FastMCP.

Каждый вызов инструмента выполняется от имени сотрудника, которому принадлежит bearer-токен. Каждый вызов инструмента сначала запрашивает разрешение у ModelAdmin. Суперпользователь может делать всё, что суперпользователь может делать в админке. Сотрудник может делать ровно то, что этот сотрудник может делать в админке, и не больше.

SPEC.md — это полная спецификация.

Как это работает

Три правила определяют пакет:

  1. Нет параллельной системы разрешений. Авторизация делегируется методам ModelAdmin: has_view_permission, has_add_permission, has_change_permission, has_delete_permission, get_queryset, get_readonly_fields и get_actions. Переопределение get_queryset, которое скрывает строки, скрывает их и от MCP.

  2. Нет параллельной поверхности данных. Записи проходят через собственную ModelForm и save_model админки, а затем записывают LogEntry. Страница истории админки остаётся правдивой.

  3. Отказ по умолчанию. Каждый неразрешённый поиск, отсутствующий ModelAdmin, неизвестное действие, неизвестное поле и неизвестный инструмент отклоняют вызов.

Related MCP server: Globalping

Установка

uv add django-admin-fastmcp

Добавьте приложение в настройки:

INSTALLED_APPS = [
    ...,
    "django.contrib.admin",
    "django_admin_fastmcp",
]

ADMIN_FASTMCP = {
    "SERVER_NAME": "acme-admin",
    "EXCLUDE_MODELS": ("auth.Permission", "auth.Group"),
    "WRITABLE_MODELS": (),          # empty means no writes at all
}

Смонтируйте конечные точки OAuth на том же сайте, что и админка:

# urls.py
urlpatterns = [
    # RFC 8414 fixes this one at the site root.
    path("", include("django_admin_fastmcp.well_known_urls")),
    # This prefix is yours to choose. Match it to the path in MCP_URL.
    path("admin/mcp/", include("django_admin_fastmcp.urls")),
    path("admin/", admin.site.urls),
]

Пакет не задаёт жёстко никакого префикса. Каждый URL, который рекламирует документ метаданных, берётся из reverse(), поэтому проект, который монтирует конечные точки по адресу /backoffice/oauth/, получает это в обнаружении, и клиенты следуют этому. Два правила: well-known документ должен находиться в корне, потому что клиент выводит его URL из издателя, а конечные точки должны располагаться на том же сайте, что и админка, потому что страница согласия использует cookie сессии админки.

Примените миграции:

python manage.py migrate django_admin_fastmcp

Больше ничего. Никакой регистрации по моделям, никаких миксинов, никаких декораторов. Сервер предоставляет то, что уже предоставляет админка.

Подключение клиента

Запустите сервер (см. Развертывание), затем зарегистрируйте его:

# Claude Code
claude mcp add --transport http acme-admin https://<host>/admin/mcp

Используйте путь без завершающего слэша. /admin/mcp/ отвечает редиректом 307 на /admin/mcp, и не каждый клиент следует редиректу на POST.

Никакого токена, никакого заголовка. Первый вызов запускает стандартный поток MCP OAuth:

  1. Клиент открывает ваш браузер на странице авторизации на сайте Django.

  2. Ваша cookie сессии админки идентифицирует вас. Если вы вышли из системы, сначала появится обычный вход в админку.

  3. Страница согласия показывает имя клиента и что означает одобрение. Вы одобряете.

  4. Клиент получает свои токены и подключается. Он обновляет их самостоятельно.

Любой MCP-клиент, который говорит на потоковом HTTP с OAuth, работает так же, например Cursor или FastMCP Client.

Правила доступа:

  • Любой сотрудник может авторизовать клиента только для себя.

  • Разрешение действует с вашими собственными правами админки, никогда не больше. Нет отдельной системы разрешений: кто может изменять модель в админке, тот может изменять её через MCP, когда сервер перечисляет эту модель в WRITABLE_MODELS.

  • Refresh-токены истекают через REFRESH_TOKEN_TTL_DAYS (по умолчанию 90), поэтому повторное согласие происходит так часто. Отзыв — это действие админки в списке изменений разрешений.

Инструменты

Одиннадцать общих инструментов, смонтированных в пространстве имён admin, поэтому имена проводов — admin_list_models и так далее. Каждый принимает model как "app_label.ModelName". Список инструментов статичен. Что меняется для каждого пользователя — это то, что каждый инструмент позволяет этому пользователю видеть и делать.

Чтение

Инструмент

Аргументы

Возвращаемое значение

list_models

нет

Каждая доступная модель, которую этот вызывающий может просматривать, с флагами разрешений.

describe_model

model

Поля, отображение списка, фильтры, поля поиска, поля только для чтения и доступные действия.

search_objects

model, q, filters, order_by, page, page_size

Строки плюс total. q использует собственный поиск админки. Неизвестный фильтр — ошибка.

get_object

model, pk

Один сериализованный экземпляр.

object_history

model, pk

Записи журнала админки для этого объекта, сначала новые.

recent_actions

limit

Записи журнала админки, ограниченные вызывающим, если вызывающий не суперпользователь.

Запись

Инструменты записи требуют, чтобы модель была указана в WRITABLE_MODELS; ваши собственные права админки решают остальное, для каждой модели и каждого объекта. Модель вне списка отказывает в любой записи и любом действии, кто бы ни вызывал. Оставьте чувствительные модели вне списка, например журнал событий, и ни один MCP-клиент никогда не сможет в них писать.

Инструмент

Аргументы

Поведение

create_object

model, data

Проверяет через форму админки, затем сохраняет и записывает в журнал.

update_object

model, pk, data

Частичное обновление. Поля только для чтения игнорируются.

delete_object

model, pk, confirm

Без confirm возвращает точный каскад удаления и ничего не меняет.

run_action

model, action, pks, confirm

Выполняет действие админки. Без confirm возвращает предпросмотр.

autocomplete

model, field, q

Разрешает значение внешнего ключа в первичный ключ, ища в связанной модели.

Каждая возвращаемая строка несёт pk как строку и admin_url, чтобы агент мог передать человеку ссылку в реальную админку.

Настройки

Все ключи находятся в словаре ADMIN_FASTMCP. Неизвестный ключ — ошибка при запуске.

Ключ

По умолчанию

Значение

SERVER_NAME

"django-admin"

Имя, которое рекламирует MCP-сервер.

ADMIN_SITE

"django.contrib.admin.site"

Точечный путь к AdminSite.

MODELS

()

Белый список "app_label.ModelName". Если не пусто, ничего больше не раскрывается.

EXCLUDE_MODELS

()

Чёрный список. Поддерживает "app_label.*".

WRITABLE_MODELS

()

Модели, которые принимают записи. Пусто означает отсутствие записей, кто бы ни вызывал.

DISABLED_TOOLS

()

Имена инструментов, полностью удалённые из каталога.

REDACT_FIELDS

("password", "token", "secret", "api_key", "private_key")

Подстрока в именах полей. Значения читаются как "[redacted]".

MAX_PAGE_SIZE

200

Ограничение размера страницы для search_objects.

MAX_PKS

1000

Ограничение pks для run_action.

ACCESS_TOKEN_TTL_MINUTES

60

Время жизни access-токена. Клиенты обновляют его с помощью refresh-токена.

REFRESH_TOKEN_TTL_DAYS

90

Время жизни refresh-токена. Повторное согласие происходит так часто.

SITE_URL

"http://127.0.0.1:8000"

Публичный URL сайта Django. Это издатель OAuth, и MCP-сервер называет его своим сервером авторизации.

MCP_URL

"http://127.0.0.1:8765/admin/mcp"

Публичный URL конечной точки MCP.

Установите SITE_URL и MCP_URL для любого реального развертывания. MCP_URL — единственный источник трёх вещей, которые должны совпадать: путь, по которому обслуживается конечная точка, resource, который рекламирует обнаружение, и аудитория, к которой привязан каждый токен. Его путь по умолчанию — /admin/mcp. Проверка при запуске отказывает в MCP_URL без пути, потому что тогда весь origin был бы объявлен защищённым ресурсом.

Настройки для каждого ModelAdmin

Установите их в классе ModelAdmin, миксин не нужен:

class InvoiceAdmin(admin.ModelAdmin):
    mcp_expose = False                     # hide this model from MCP entirely
    mcp_fields = ("number", "total")       # allowlist of serialized fields
    mcp_exclude_fields = ("internal_note",)  # denylist of serialized fields

REDACT_FIELDS имеет приоритет над mcp_fields. Явное перечисление поля пароля не раскрывает его.

Безопасность

MCP-сервер админки для суперпользователя — это удалённая оболочка над производственной базой данных, управляемая языковой моделью. Ограничения:

  • WRITABLE_MODELS по умолчанию пуст, поэтому ни одна модель не принимает записи, пока развертывание не назовёт её. Всё остальное — ваши обычные разрешения Django, запрашиваемые через ModelAdmin при каждом вызове.

  • Access-токены недолговечны. Хранятся только солёные хэши, поэтому утёкшая строка базы данных не может быть воспроизведена.

  • delete_object и run_action по умолчанию показывают предпросмотр и ничего не меняют до confirm=True.

  • Каждая мутация записывает LogEntry, приписанный пользователю разрешения, с именем клиента в сообщении об изменении, например "Changed status. Via MCP (client: Claude Code).". Запись, которая не может записать LogEntry, откатывается.

  • Собственные модели пакета, sessions.Session и authtoken.Token никогда не раскрываются, что бы ни говорили настройки.

  • Держите auth.Permission и auth.Group вне WRITABLE_MODELS. Агент, который может выдавать разрешения, может выйти за пределы модели разрешений.

Развертывание

Отдельный процесс. Запустите MCP-сервер рядом с вашим проектом Django:

python manage.py admin_mcp_serve

Он обслуживает путь из MCP_URL, который по умолчанию /admin/mcp, на порту из MCP_URL, или 8765, если этот URL не указывает порт. Оба можно переопределить с помощью --host и --port. Ничего в вашей существующей конфигурации обслуживания не меняется. Направьте /admin/mcp через ваш ingress на этот порт и убедитесь, что заголовок Authorization проходит.

Смонтированный (M3). Смонтируйте сервер по адресу /admin/mcp внутри asgi.py вашего проекта. Одно ограничение: диспетчеризация по точному пути. Конечные точки OAuth находятся непосредственно под тем же префиксом (/admin/mcp/authorize и другие), и Django должен продолжать их обслуживать, поэтому диспетчер, который отправляет всё под /admin/mcp в FastMCP, поглотил бы их. Рецепт поставляется с вехой M3.

Сервер не имеет состояния, поэтому любой экземпляр за балансировщиком нагрузки может обслуживать любой запрос.

Разработка

make install     # bootstrap uv, pin Python, install dependencies
make test        # run the permission matrix
make check       # format, lint, typecheck, and test
make migrate     # migrate the test project
make serve       # run the MCP server against the test project on :8765/admin/mcp
make help        # everything else

Лицензия

MIT

Related MCP Connectors

Related MCP Servers