django-admin-fastmcp
django-admin-fastmcp
一个可复用的 Django 应用,将 Django admin 暴露为 MCP 服务器,基于 FastMCP 构建。
每次工具调用都会以后台用户(即该 bearer token 的拥有者)身份执行。每次工具调用都会先向
ModelAdmin 请求权限。超级用户可以做到超级用户在 admin 中能做的所有事。staff 用户
则只能做到该 staff 用户在 admin 中能做的事,除此之外没有任何额外权限。
SPEC.md 是完整规范。
工作原理
三条规则定义了整个包:
没有另一套并行的权限系统。 授权全部委托给
ModelAdmin的方法:has_view_permission、has_add_permission、has_change_permission、has_delete_permission、get_queryset、get_readonly_fields和get_actions。 如果覆写了get_queryset来隐藏某些行,那么这些行对 MCP 也同样隐藏。没有另一套数据面。 写入操作走 admin 自己的
ModelForm和save_model,然后记录LogEntry。admin 的历史页面保持真实。默认拒绝。 任何无法解析的查找、缺失的
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 流程:
客户端在你的浏览器中打开 Django 站点上的授权页面。
你的 admin 会话 cookie 会识别你的身份。如果已经退出登录,会首先显示普通的 admin 登录页。
同意页面会显示客户端名称以及批准所代表的意义。你点击批准。
客户端收到 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 display、筛选器、搜索字段、只读字段和可用动作。 |
|
| 返回行及 |
|
| 一个序列化后的实例。 |
|
| 该对象的 admin 日志条目,最新在前。 |
|
| admin 日志条目,默认限定为调用者,调用者为超级用户时除外。 |
写入
写工具要求模型被列入 WRITABLE_MODELS;剩下的决定权仍然根据你自己的 admin
权限,按模型、按对象进行。列表之外的模型,无论调用者是谁,都会拒绝所有写入操作
和所有动作。把敏感模型留在外面,例如事件日志,这样任何 MCP 客户端都无法向它们写入。
工具 | 参数 | 行为 |
|
| 通过 admin 表单验证,然后保存并记录日志。 |
|
| 部分更新。只读字段会被忽略。 |
|
| 没有 |
|
| 运行 admin 动作。没有 |
|
| 通过搜索关联模型,把外键值解析为主键值。 |
每个返回的行都会带上字符串形式的 pk 和 admin_url,因此 agent 可以把
一个进入真实 admin 的链接交给人类用户。
设置
所有键都放在 ADMIN_FASTMCP 字典中。未知的键会在启动时触发错误。
键 | 默认值 | 含义 |
|
| MCP 服务器对外公布的名称。 |
|
|
|
|
| 白名单,格式为 |
|
| 黑名单。支持 |
|
| 接受写入的模型。为空表示无论谁调用都不允许写入。 |
|
| 从工具目录中完全移除的工具名称。 |
|
| 对字段名称做子字符串匹配。匹配到的字段值显示为 |
|
|
|
|
| 每次 |
|
| 访问令牌的有效期。客户端使用刷新令牌续期。 |
|
| 刷新令牌的有效期。达到这一时长就需要重新授权。 |
|
| Django 站点的公开 URL。它是 OAuth issuer,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 fieldsREDACT_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 elseLicense
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
MCP server for AI dialogue using various LLM models via AceDataCloud
Related MCP Servers
- AlicenseBqualityCmaintenanceAn MCP server that provides LLMs access to other LLMs433 npm79MIT

Globalpingofficial
FlicenseNot gradedqualityBmaintenanceRemote MCP server that gives LLMs access to run network commands64-- AlicenseDqualityBmaintenanceExposes OpenWebUI's admin REST API as an MCP server, enabling administrative operations on OpenWebUI through natural language via MCP tools.1002MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for LambdaMOO administration. Connects to a MOO's admin port over TCP and exposes tools for eval, verb/property management, and inheritance chain walking.MIT