Skip to main content
Glama
edelvalle

django-admin-fastmcp

by edelvalle

django-admin-fastmcp

Una aplicación Django reutilizable que expone el admin de Django como un servidor MCP, construida sobre FastMCP.

Cada llamada a una herramienta se ejecuta como el usuario del staff que posee el token de portador. Cada llamada a una herramienta pide permiso a ModelAdmin en primer lugar. Un superusuario puede hacer todo lo que un superusuario puede hacer en el admin. Un usuario del staff puede hacer exactamente lo que ese usuario del staff puede hacer en el admin, y nada más.

SPEC.md es la especificación completa.

Cómo funciona

Tres reglas definen el paquete:

  1. Sin sistema de permisos paralelo. La autorización se delega en los métodos de ModelAdmin: has_view_permission, has_add_permission, has_change_permission, has_delete_permission, get_queryset, get_readonly_fields y get_actions. Una sobreescritura de get_queryset que oculta filas las oculta también para MCP.

  2. Sin superficie de datos paralela. Las escrituras pasan por el ModelForm y el save_model propios del admin, y luego registran un LogEntry. La página de historial del admin se mantiene fiel.

  3. Cierre de fallos. Toda búsqueda no resuelta, ModelAdmin ausente, acción desconocida, campo desconocido y herramienta desconocida deniega la llamada.

Instalación

uv add django-admin-fastmcp

Añade la aplicación a tus ajustes:

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
}

Monta los endpoints de OAuth en el mismo sitio que el admin:

# 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),
]

El paquete no fija ningún prefijo hardcodeado. Cada URL que anuncia el documento de metadatos sale de reverse(), así que un proyecto que monte los endpoints en /backoffice/oauth/ lo verá en el descubrimiento y los clientes lo seguirán. Dos reglas: el documento well-known debe estar en la raíz, porque un cliente deriva su URL del emisor, y los endpoints deberían estar en el mismo sitio que el admin, porque la página de consentimiento se apoya en la cookie de sesión del admin.

Aplica las migraciones:

python manage.py migrate django_admin_fastmcp

Nada más. Sin registro por modelo, sin mixins, sin decoradores. El servidor expone lo que el admin ya expone.

Conectar un cliente

Ejecuta el servidor (consulta Implementación) y regístralo:

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

Usa la ruta sin barra final. /admin/mcp/ responde con una redirección 307 a /admin/mcp, y no todos los clientes siguen una redirección en POST.

Sin token, sin cabecera. La primera llamada inicia el flujo OAuth estándar de MCP:

  1. El cliente abre tu navegador en la página de autorización del sitio Django.

  2. Tu cookie de sesión del admin te identifica. Si no tienes la sesión iniciada, aparece primero el login normal del admin.

  3. Una página de consentimiento muestra el nombre del cliente y lo que significa la aprobación. Tú apruebas.

  4. El cliente recibe sus tokens y se conecta. Los renueva por sí solo.

Cualquier cliente de MCP que hable HTTP streamable con OAuth funciona de la misma manera, por ejemplo Cursor o un Client de FastMCP.

Reglas sobre el acceso:

  • Cualquier usuario del staff puede autorizar un cliente, solo para sí.

  • Un acceso actúa con sus propios permisos de admin, nunca con más. No existe un sistema de permisos aparte: quien tenga permiso para cambiar un modelo en el admin podrá cambiarlo por MCP, siempre que el servidor tenga ese modelo en WRITABLE_MODELS.

  • Los tokens de refresco caducan tras REFRESH_TOKEN_TTL_DAYS (90 por defecto), así que el re-consentimiento ocurre con esa frecuencia. La revocación es una acción del admin sobre la lista de cambios de las autorizaciones.

Herramientas

Once herramientas genéricas, montadas bajo el espacio de nombres admin, por eso los nombres que viajan por el protocolo son admin_list_models y similares. Cada una recibe model como "app_label.ModelName". La lista de herramientas es estática. Lo que varía por usuario es qué puede ver y hacer ese usuario con cada herramienta.

Lectura

Herramienta

Argumentos

Devuelve

list_models

ninguno

Cada modelo expuesto que este llamador pueda ver, con los indicadores de permisos.

describe_model

model

Campos, visualización de lista, filtros, campos de búsqueda, campos de solo lectura y acciones disponibles.

search_objects

model, q, filters, order_by, page, page_size

Filas además de total. q usa la búsqueda propia del admin. Un filtro desconocido es un error.

get_object

model, pk

Una instancia serializada.

object_history

model, pk

Entradas de log del admin para ese objeto, la más reciente primero.

recent_actions

omitir

Entradas de log del admin, contextuales al llamador salvo si el llamador es superusuario.

Escritura

Las herramientas de escritura exigen que el modelo esté en WRITABLE_MODELS; tus propios permisos de admin deciden el resto, por modelo y por objeto. Un modelo fuera de la lista rechaza toda escritura y toda acción, llame quien llame. Deja fuera los modelos sensibles, por ejemplo un registro de eventos, y ningún cliente MCP podrá escribirlos jamás.

Herramienta

Argumentos

Comportamiento

create_object

model, data

Valida con el formulario del admin y luego guarda y registra.

update_object

model, pk, data

Actualización parcial. Los campos de solo lectura se ignoran.

delete_object

model, pk, confirm

Sin confirm, devuelve la cascada de borrado exacta y no cambia nada.

run_action

model, action, pks, confirm

Ejecuta una acción del admin. Sin confirm, devuelve una vista previa.

autocomplete

model, field, q

Resuelve un valor de clave foránea a una clave primaria buscando en el modelo relacionado.

Cada fila devuelta incluye pk como cadena y un admin_url, de modo que un agente puede ofrecer a una persona un enlace al admin real.

Ajustes

Todas las claves viven en el diccionario ADMIN_FASTMCP. Una clave desconocida es un error al inicio.

Clave

Default

Significado

SERVER_NAME

"django-admin"

Nombre que anuncia el servidor MCP.

ADMIN_SITE

"django.contrib.admin.site"

Ruta con puntos hacia el AdminSite.

MODELS

()

Lista de permitidos de "app_label.ModelName". Cuando no está vacía, no se expone nada más.

EXCLUDE_MODELS

()

Lista de denegados. Admite "app_label.*".

WRITABLE_MODELS

()

Modelos que aceptan escrituras. Vacía significa que no se escribe, llame quien llame.

DISABLED_TOOLS

()

Nombres de herramientas eliminadas del catálogo por completo.

REDACT_FIELDS

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

Coincidencia por substrings en los nombres de campo. Los valores se leen como "[redacted]".

MAX_PAGE_SIZE

200

Límite máximo del tamaño de página en search_objects.

MAX_PKS

1000

Límite de pks por run_action.

ACCESS_TOKEN_TTL_MINUTES

60

Tiempo de vida del token de acceso. Los clientes lo renuevan con el token de renovación.

REFRESH_TOKEN_TTL_DAYS

90

Tiempo de vida del token de renovación. La reautorización se produce con esa frequent.

SITE_URL

"http://127.0.0.8:8000"

URL pública del sitio Django. Es el emisor de OAuth, y el servidor MCP lo designa como su servidor de autorización.

MCP_URL

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

URL pública del endpoint MCP.

Establece SITE_URL y MCP_URL en cualquier implementación real. MCP_URL es la única fuente de tres cosas que deben coincidir: la ruta en la que sirve el endpoint, el resource que anuncia el descubrimiento y la audiencia a la que está vinculado cada token. Su ruta por defecto es /admin/mcp. Una comprobación de inicio rechaza una MCP_URL sin ruta, porque entonces se anunciaría todo el origen como recurso protegido.

Opciones por ModelAdmin

Estos valores se ponen en una clase ModelAdmin, sin necesidad de mixin:

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 tiene prioridad sobre mcp_fields. Incluir explícitamente un campo de contraseña no lo revela.

Seguridad

Un servidor MCP de admin para un superusuario es un shell remoto sobre la base de datos de producción, guiado por un modelo de lenguaje. Las salvaguardias:

  • WRITABLE_MODELS está vacío por defecto, así que ningún modelo acepta escrituras hasta que el despliegue lo indique. Todo lo demás son los permisos normales de Django, consultados a partir del ModelAdmin en cada llamada.

  • Los tokens de acceso son de corta duración. Solo se almacenan hashes con sal, de modo que una fila filtrada de la base de datos no puede reproducirse.

  • delete_object y run_action muestran una vista previa en ayudante por defecto y no cambian nada hasta que confirm=True.

  • Cada mutación registra un LogEntry atribuido al usuario de la autoriz, con el nombre del cliente en el mensaje de cambio, por ejemplo "Changed status. Via MCP (client: Claude Code).". Una escritura que no puede registrar un LogEntry se revierte.

  • Los modelos propios del paquete, por ejemplo sessions.Session y authtoken.Token, no se exponen nunca, sin importar lo que digan los ajustes.

  • Mantén auth.Permission y auth.Group fuera de WRITABLE_MODELS. Un agente que puede otorgar permisos puede escapar del modelo de permisos.

Implementación

Proceso separado. Ejecuta el servidor MCP junto a tu proyecto:

python manage.py admin_mcp_serve

Sirve la ruta de MCP_URL, que por defecto es /admin/mcp, en el puerto de MCP_URL, o 8765 cuando la URL no define puerto. Ambos son configurable con --host y --port. No cambia nada de tu configuración de serviro existente. Encamina /admin/mcp a ese puerto a través de tu entrada, y asegúrate de que la cabecera Authorization pase.

Montado (M3). Monta el servidor en /admin/mcp dentro de tu archivo asgi.py. Una restricción: distribuye en la ruta exacta. Los endpoints de OAuth viven justo debajo del mismo prefijo (/admin/mcp/authorize y otros) y Django debe seguir sirviendo esos, así que un dispatcher que mande todo lo que esté bajo /admin/mcp a FastMCP se los tragaría. La receta se entrega con el hito M3.

El servidores sin estado, por lo que cualquier instancia detrás de un balanceador de carga puede servir cualquier solicitud.

Desarrollo

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

Licencia

MIT

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

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

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • MCP server for AI dialogue using various LLM models via AceDataCloud

  • An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform

  • Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer

View all MCP Connectors

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/edelvalle/django-admin-fastmcp'

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