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、未知的动作、未知的字段 以及未知的工具调用,都会被拒绝。
安装
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 installed
Maintenance
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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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