canvas-admin-roster — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited canvas-admin-roster (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Admin-audience skill for inspecting the Canvas account tree and making targeted enrollment changes. Walks list_accounts → list_sub_accounts → list_account_courses / list_account_users so the agent paces itself instead of dumping the whole institution at once. Write paths (enroll_user, remove_enrollment) are explicitly gated by per-action confirmation and are clearly separated from the read paths.
list_accounts and 401/403 from list_sub_accounts, list_account_courses, list_account_users, and get_account_reports. If the user does not have an admin token, stop at Step 1 and tell them this skill needs an admin role on the relevant account.enroll_user and remove_enrollment additionally require permission to manage enrollments on the target course. A "subaccount admin" role may be able to read the account but not modify enrollments — the skill will surface a 403 if that happens.Call list_accounts. This returns every account the authenticated admin has access to — in many institutions this is just the root account, but multi-tenant Canvas deployments can return several.
If the response is empty, the token does not have admin scope. Stop here and tell the user.
Show the user the accounts with their id, name, and parent_account_id:
ACCOUNTS YOU CAN ADMIN
• [1] Root Account (Big State University)
• [42] College of Engineering parent: 1
• [43] College of Liberal Arts parent: 1Ask the user which account to drill into, or default to the root account.
For the chosen account, call list_sub_accounts with that account_id. This is shallow — it returns direct children only, not the full descendant tree. If the user wants to walk further down, repeat list_sub_accounts on each child sub-account they pick. Do not recurse the whole tree by default — large institutions can have hundreds of sub-accounts and you will burn quota.
SUB-ACCOUNTS UNDER [42] College of Engineering
• [120] Department of Computer Science parent: 42
• [121] Department of Mechanical Eng. parent: 42
• [122] Department of Electrical Eng. parent: 42If the user wants metadata for a specific account (settings, default time zone, sis identifier, etc.), call get_account with that account_id and surface the fields they asked for.
For the chosen account, call list_account_courses with the account_id. Optional search_term narrows by course name or course code.
The result is paginated under the hood. Present a count first ("Found 187 courses in [account]"), then offer:
| Mode | When to use |
|---|---|
| Filter by name | Re-call with a search_term (e.g. "CS 101") |
| Show first N | Display the first 25 by default; offer to page further only if asked |
| Group by sub-account | Group locally; do not re-query per sub-account |
For very large accounts (1000+ courses), tell the user: filter by search_term first. Pulling the full list works but is slow and crowds the agent's context.
For the chosen account, call list_account_users with the account_id. Optional search_term searches name, email, and login ID.
Users can have many enrollments across many courses; this endpoint returns each user once with account-level metadata, not their enrollments. Combine with Step 6 (course enrollments) if the user asks "what is this person enrolled in".
USERS IN [120] CS Department (search: "park")
• [88321] Jordan Park login: jpark email: [email protected]
• [88455] Min Park login: minpark email: [email protected]Call get_account_reports with the account_id. This returns the list of report types Canvas can run for this account, plus metadata about the most recent instance of each — it does NOT start a new report and there is no polling endpoint exposed by this MCP server. Common report types include course_storage_csv, provisioning_csv, student_assignment_outcome_map_csv, and several SIS exports — exact set varies by Canvas instance.
For each report row, show:
report (the report type identifier)title (human-readable name)last_run (timestamp of the most recent execution, if any)parameters (any defaults the report exposes)Then tell the user explicitly:
"These are the report types available to you. To actually run one of these reports, use the Canvas web UI under Admin → [Account] → Settings → Reports. canvas-lms-mcp does not expose astart_report/get_report_statustool surface, so the run must happen in the UI and you can come back here once the export is downloadable."
Do not invent a polling loop. Do not pretend to "wait for the report" — there is nothing to poll.
list_account_users does not include enrollment lists. To see who is enrolled in a particular course, call list_course_enrollments with the course_id (you'll have it from Step 3). Filter by type and state as needed:
type=['StudentEnrollment'] for studentstype=['TeacherEnrollment','TaEnrollment'] for instructional staffstate=['active'] to skip pending invites and concluded enrollmentsA note about list_enrollments (singular, no course_ prefix): that tool returns the authenticated user's own enrollments — /api/v1/users/self/enrollments. It is useful for checking "what courses am I admin/teacher in?" but it is not a way to look up some other user's enrollment list. There is no tool in this MCP server that fetches arbitrary-user enrollments across courses; you would have to walk list_account_courses and list_course_enrollments per course, which is expensive.
Requires explicit user confirmation before each call.
When the admin wants to add an enrollment:
StudentEnrollment — studentTeacherEnrollment — teacherTaEnrollment — TADesignerEnrollment — learning designerObserverEnrollment — observer (e.g., parent)enrollment_state: active (immediately enrolled), invited (default — sends Canvas invitation), or inactive."Enroll user [Name] (id [n]) into [Course Name] (id [c]) as [Type], state=[State]? (yes/no)"
enroll_user with course_id, user_id, type, and enrollment_state if specified.enrollment_id (needed for Step 8 if the admin later wants to revoke it).Never batch. If the admin wants to enroll five users, repeat steps 1–7 five times with five separate confirmations. Do not collapse them into one prompt.
Requires explicit user confirmation before each call. This is destructive: depending on the task, it can permanently delete the enrollment record.
enrollment_id to remove (from list_course_enrollments output, not the user_id — the tool takes enrollment_id).task:conclude — soft-end the enrollment, preserves grades and submissions for the userdelete — hard-delete the enrollment row (user loses access immediately; submissions remain in the course but are detached from this enrollment)deactivate — set the enrollment to inactive (user keeps record but loses course access until reactivated)"[Task] enrollment [enrollment_id] for [User Name] in [Course Name]? This [conclude/delete/deactivate]s the enrollment. (yes/no)"
remove_enrollment with course_id, enrollment_id, and task.✓ [Task]d enrollment [enrollment_id].If the admin asks to "remove a user", default to conclude unless they explicitly request delete. conclude is reversible by re-enrolling the user; delete may not be.
Admin Roster — Big State University
ACCOUNT TREE
• [1] Root Account
• [42] College of Engineering 187 courses, 4,021 users
• [120] Computer Science 52 courses
• [121] Mechanical Engineering 38 courses
• [43] College of Liberal Arts 243 courses, 3,108 users
WRITES THIS SESSION
• Enrolled Casey Chen → CS 101 (StudentEnrollment, active) ✓ id 991204
• Concluded Pat Kim → CS 200 (enrollment 887211, task=conclude) ✓
• Reports for [42]: 6 types available — see web UI to runlist_sub_accounts returns direct children only. There is no get_account_tree aggregator; resist the urge to recurse the whole tree by default.start_report, no get_report_status, and no download_report. To actually run a report, the admin uses the Canvas web UI. State this plainly when the user asks "can you run the [foo] report".list_course_enrollments per course instead, or list_account_users for account-level user discovery.list_course_enrollments output before calling remove_enrollment.active. If the admin wants immediate access, pass enrollment_state: 'active' explicitly.list_account_users and list_account_courses can return institution-wide PII. Treat this output the same as a payroll export — do not paste into shared chats or screen-share without redacting.search_term filter first and ask the admin to narrow before pulling the full list.list_sub_accounts, list_account_users, or get_account_reports means the admin role does not have access to that specific sub-account, even if list_accounts returned the parent. Surface the 403 verbatim — do not silently retry.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.