Security & scopes
Authentication
Section titled “Authentication”Two accepted credentials:
X-MCP-Key— anMCPKeybearer minted from Django admin.- The platform’s own JWT / session — an Open edX JWT already encodes
is_staff/is_superuser, so the same endpoints work with a raw platform token too.
Authorization — one live gate
Section titled “Authorization — one live gate”Whichever credential authenticates, the rule is identical and re-checked live on
every request: the acting user must be is_staff or is_superuser right now.
Demote them and every key they hold stops working on the next call. A key never
caches privilege; scopes only ever narrow it.
Scopes
Section titled “Scopes”Tick scopes per key for least privilege. A superuser bypasses narrowing.
| Scope | Gates |
|---|---|
read | whoami, analytics, listings, roles, grades, cert/report status |
write:enrollment | enroll, unenroll, bulk_enroll |
write:users | create_user, reset_student_attempts |
write:roles | set_role (course roles), instructor_access |
grant:admin | set_role for global_staff / superuser (escalation) |
write:certificates | generate / regenerate certificates |
write:reports | submit async reports (grade export, …) |
write:courses | block CRUD, create_block_tree, update_course_settings |
destructive | additive — deactivate_user, request_retirement, invalidate_certificate, delete block |
destructive is additive: a destructive tool needs its domain scope and
destructive, so a key can never delete without also holding the relevant write
scope. Granting platform admin is isolated behind grant:admin, so an ops key can
manage course staff without ever being able to mint a superuser.
Write rails
Section titled “Write rails”Every state-changing tool passes through four rails:
- Live authority re-check — the gate above, per request.
- Rate limit — per-
(key, tool)fixed window; turns a runaway agent into ~N calls instead of thousands. Mass tools (bulk enroll, retire) get the tightest budgets. - Dry-run + confirm token — high-impact / destructive tools first return a preview plus a single-use token bound to a fingerprint of the exact payload. Re-send with the token to apply; changing any argument invalidates it.
- Append-only audit — intent is recorded before the write, and the write is refused if that record can’t be persisted.