Skip to main content
Glama
edelvalle

django-admin-fastmcp

by edelvalle

django-admin-fastmcp

一个可复用的 Django 应用,将 Django admin 暴露为 MCP 服务器,基于 FastMCP 构建。

每次工具调用都会以后台用户(即该 bearer token 的拥有者)身份执行。每次工具调用都会先向 ModelAdmin 请求权限。超级用户可以做到超级用户在 admin 中能做的所有事。staff 用户 则只能做到该 staff 用户在 admin 中能做的事,除此之外没有任何额外权限。

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. 没有另一套数据面。 写入操作走 admin 自己的 ModelForm 和 save_model,然后记录 LogEntry。admin 的历史页面保持真实。

  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
}

在同 admin 站点下绑定 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 文档必须位于根路径,因为客户端会凭 issuer 推导出它的 URL;端点也应该和 admin 放在同一个站点,因为同意页面依赖 admin 的会话 cookie。

执行迁移:

python manage.py migrate django_admin_fastmcp

仅此而已。不需要逐模型注册,不需要 mixin,不需要装饰器。服务器会把 admin 已经暴露的 内容原样暴露出来。

连接客户端

运行服务器(参见部署),然后注册它:

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

使用不带尾部斜杠的路径。/admin/mcp/ 会返回 307 重定向到 /admin/mcp,但并不是所有客户端都会在 POST 请求时跟随重定向。

没有 token,也没有请求头。第一次调用就会启动标准的 MCP OAuth 流程:

  1. 客户端在你的浏览器中打开 Django 站点上的授权页面。

  2. 你的 admin 会话 cookie 会识别你的身份。如果已经退出登录,会首先显示普通的 admin 登录页。

  3. 同意页面会显示客户端名称以及批准所代表的意义。你点击批准。

  4. 客户端收到 token 并连接。之后它会自行续约。

任何支持带 OAuth 的 streamable HTTP 的 MCP 客户端都能以相同方式工作, 例如 Cursor,或 FastMCP Client。

访问规则:

  • 任何 staff 用户都可以为自己授权客户端,而且只能为自己。

  • 授权记录只拥有你自己 admin 权限,绝不会多。没有其他权限系统: 遵循 admin 中能修改某模型的人,在服务器把该模型列入 WRITABLE_MODELS 后, 也同样能通过 MCP 修改它。

  • 刷新 token 会在 REFRESH_TOKEN_TTL_DAYS(默认 90 天)后过期,因此 重新授权也会按这个频率发生。撤销授权是在授权记录 changelist 中的一项管理操作。

工具

十一个通用工具,挂载在 admin 命名空间下,因此它们的 wire 名称是 admin_list_models 等。每个工具都接受 model,格式为 "app_label.ModelName"。工具列表 是静态的。用户之间的差异只在于每个工具允许使用者看到什么、做什么。

读取

工具

参数

返回

list_models

无

调用者可以查看的所有已暴露模型,以及权限标记。

describe_model

model

字段、list display、筛选器、搜索字段、只读字段和可用动作。

search_objects

model、q、filters、order_by、page、page_size

返回行及 total。q 使用 admin 自己的搜索。未知筛选器会报错。

get_object

model、pk

一个序列化后的实例。

object_history

model、pk

该对象的 admin 日志条目,最新在前。

recent_actions

limit

admin 日志条目,默认限定为调用者,调用者为超级用户时除外。

写入

写工具要求模型被列入 WRITABLE_MODELS;剩下的决定权仍然根据你自己的 admin 权限,按模型、按对象进行。列表之外的模型,无论调用者是谁,都会拒绝所有写入操作 和所有动作。把敏感模型留在外面,例如事件日志,这样任何 MCP 客户端都无法向它们写入。

工具

参数

行为

create_object

model、data

通过 admin 表单验证,然后保存并记录日志。

update_object

model、pk、data

部分更新。只读字段会被忽略。

delete_object

model、pk、confirm

没有 confirm 时,返回精确的删除级联结果,且不作出任何更改。

run_action

model、action、pks、confirm

运行 admin 动作。没有 confirm 时可返回预览。

autocomplete

model、field、q

通过搜索关联模型,把外键值解析为主键值。

每个返回的行都会带上字符串形式的 pk 和 admin_url,因此 agent 可以把 一个进入真实 admin 的链接交给人类用户。

设置

所有键都放在 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

每次 run_action 中 pks 数量的上限。

ACCESS_TOKEN_TTL_MINUTES

60

访问令牌的有效期。客户端使用刷新令牌续期。

REFRESH_TOKEN_TTL_DAYS

90

刷新令牌的有效期。达到这一时长就需要重新授权。

SITE_URL

"http://127.0.0.1:8000"

Django 站点的公开 URL。它是 OAuth issuer,MCP 服务器也将它标记为授权服务器。

MCP_URL

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

MCP 端点的公开 URL。

任何真实部署都必须设置 SITE_URL 和 MCP_URL。MCP_URL 是三件必须一致的事的 唯一定义来源:端点实际服务的路径、发现文档公布的 resource,以及每个令牌绑定的 audience。其路径默认为 /admin/mcp。启动检查会拒绝一个不带路径的 MCP_URL, 因为那样的话整个源会被作为受保护资源公布。

每个 ModelAdmin 的配置项

把以下配置放在某个 ModelAdmin 类上,不需要 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 优先于 mcp_fields。即使你显式列出密码字段, 也不会把它暴露出去。

安全

一个对超级用户开放的 admin MCP 服务器,就是一个由语言模型驱动的、架在生产数据库上的 远程 shell。护栏如下:

  • WRITABLE_MODELS 默认是空的,因此在部署时显式列出之前,没有模型会接受写入。 其余的一切都是你常规的 Django 权限,每次调用都会通过 ModelAdmin 进行询问。

  • 访问令牌有效期很短。数据库只保存加盐哈希,因此即使数据库行泄露 也无法被重放。

  • 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。 能够授予权限的 agent 可以逃出权限模型。

部署

独立进程。 在 Django 项目旁边运行 MCP 服务器:

python manage.py admin_mcp_serve

它从 MCP_URL 中取得路径,也就是默认的 /admin/mcp,并使用 MCP_URL 中的端口; 如果 URL 中没有端口则使用 8765。两者都可以用 --host 和 --port 覆盖。 你现有的任何服务配置都不需要改变。把 /admin/mcp 通过 ingress 路由到该端口, 并确保 Authorization 头被传递过来。

挂载(M3)。 在项目的 asgi.py 中将服务器挂载到 /admin/mcp。 有一个约束:必须按完整路径进行分发。OAuth 端点也位于同一个前缀之下 (/admin/mcp/authorize 等),Django 必须继续为它们提供服务, 因此如果你把 /admin/mcp 下的所有内容都交给 FastMCP,会把那些 OAuth 端点 全部吞掉。本配方随里程碑 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

License

MIT

Related MCP Connectors

Related MCP Servers