Canvas LMS MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| CANVAS_BASE_URL | Yes | Canvas instance URL (e.g., https://school.instructure.com) | |
| CANVAS_API_TOKEN | Yes | Canvas personal access token | |
| CANVAS_PSEUDONYM_DIR | No | Absolute path that overrides the default pseudonym map directory | |
| CANVAS_ALLOWED_ORIGIN | No | CORS origin for HTTP mode (default: http://localhost:3000) | |
| CANVAS_PSEUDONYM_AUDIT_LOG | No | Path to an append-only file that mirrors resolve_pseudonym audit lines | |
| CANVAS_PSEUDONYMIZE_STUDENTS | No | Set to 'true' to enable FERPA mode student pseudonymization | |
| CANVAS_PSEUDONYMIZE_REVERSE_LOOKUP | No | Set to 'true' (with CANVAS_PSEUDONYMIZE_STUDENTS=true) to register the resolve_pseudonym audit tool |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| prompts | {
"listChanged": true
} |
| resources | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| health_checkA | Check if the Canvas API is reachable and the token is valid. Returns ok/error status. |
| list_coursesA | List courses for the authenticated user. Use fields="slim" when enumerating courses for selection; switch to "full" once you have identified the target. slim returns id, name, course_code, term name, and workflow_state only. "full" (default) includes all Canvas fields plus |
| get_courseA | Get details for a single course. Defaults to requesting |
| get_syllabusA | Get just the syllabus HTML body for a course, returning { course_id, syllabus_body } where syllabus_body is null if the course has none set. Use get_course with include: ['syllabus_body'] instead when you also need other course fields in the same call, or update_course to change the syllabus body. If the course has public_syllabus or public_syllabus_to_auth enabled, the body may be readable even by callers without an enrollment in the course. |
| list_sectionsA | List the sections of a course, returning each section's id, name, course_id, start_at, end_at and restrict_enrollments_to_section_dates. Use it to resolve the section ID that |
| create_courseA | Create a new course in a Canvas account and return the created Canvas course object (id, name, course_code, workflow_state, and the fields passed in). Not idempotent: calling it again with the same name creates a second, separate course rather than reusing or updating the first — use update_course afterward to change it, or list_courses first to check whether a matching course already exists. Canvas silently drops start_at and end_at unless the course also restricts enrollment to course dates, which this tool does not expose, so the dates you pass may not take effect; set them with update_course if they don't. Requires the account-level permission to create courses. |
| update_courseA | Update an existing course and return the updated Canvas course object. Only the fields you pass are changed; omitted fields are left as-is, and calling it again with the same values leaves the course in the same state (idempotent). Requires permission to update course details; a caller who has only that lesser permission (not full course update rights) can still change syllabus_body through this same call, but every other field they pass is silently dropped rather than erroring. Use create_course for a new course, or get_course to see the current values before changing them. |
| list_assignmentsA | List all assignments in a course. Use fields="slim" when enumerating assignments for selection; switch to "full" once you've identified the target. slim returns id, name, due_at, points_possible, published, and course_id only. "full" (default) includes all Canvas fields plus |
| get_assignmentA | Get the full assignment record for one assignment by ID, including every |
| list_assignment_groupsA | List assignment groups (categories like Homework, Exams) in a course. Use |
| create_assignment_groupA | Create a new assignment group (a gradebook category such as Homework or Exams) in a course and return the created Canvas assignment group object, including its |
| update_assignment_groupA | Update an existing assignment group in a course and return the updated Canvas assignment group object. Only the fields passed are changed — anything omitted keeps its current value, so repeating the same call leaves the group in the same state, unlike |
| create_assignmentA | Create a new assignment in a course and return the created assignment object. Each call creates another assignment — Canvas assigns a new ID every time, so check list_assignments with a search_term first to avoid duplicates. Use update_assignment to change an existing assignment instead of calling this again, and delete_assignment to remove one. due_at, lock_at, and unlock_at here apply to every student; to give a different date to a subset of students, a section, or a group, use create_assignment_override instead, or set_student_assignment_dates to fan a date change for one student across many assignments. Dates are ISO 8601 strings; lock_at must be after due_at and unlock_at before due_at when both are set. Requires instructor/TA permission to manage assignments and quizzes in the course. |
| update_assignmentA | Update an existing assignment in a course, changing only the fields you pass — anything omitted keeps its current value — and return the updated assignment object. Calling this again with the same arguments leaves the assignment in the same state, unlike create_assignment, which always makes a new one; use delete_assignment to remove this assignment instead. due_at, lock_at, and unlock_at set here apply to every student without an override; use create_assignment_override for a different date for one section, group, or set of students, or set_student_assignment_dates to fan one student's date change across many assignments at once. lock_at must stay after due_at and unlock_at before due_at when both are set. Requires instructor/TA permission to manage assignments and quizzes in the course. |
| delete_assignmentA | Permanently delete an assignment from a course; this cannot be undone. Returns no assignment object, only an acknowledgement that the deletion succeeded. Use update_assignment instead to change the assignment rather than remove it, or create_assignment afterward to make a new one — Canvas assigns it a new ID rather than reusing the deleted one. Requires instructor/TA permission to manage assignments and quizzes in the course. |
| list_submissionsA | List all submissions for an assignment. Use |
| get_submissionA | Get one student's submission for an assignment by user_id, returning the Canvas submission object (score, grade, workflow_state, submitted_at, body/url, submission_comments). user_id can be any user in the course, not only the caller's own. Use list_submissions to fetch every student's submission for the assignment in a single call instead of one get_submission call per student, or get_my_submissions when the caller wants their own submissions across a whole course rather than one assignment. Defaults to including submission_comments; pass |
| grade_submissionA | Post or update the grade for one student's submission on a regular assignment and return the updated Canvas submission object (score, grade, workflow_state, graded_at). Only |
| comment_on_submissionA | Add a text comment to a submission and return the updated Canvas submission object, with the new entry appended to |
| list_course_submission_filesA | List every file attachment submitted by students across all assignments in a course. Returns a manifest — one entry per file — including the original filename, a file_id for re-fetching via download_file, content type, and size. Useful for bulk-archiving student work before a course expires or a Free-For-Teacher account is concluded. Outputs are bounded by max_files (default 500); when the limit is hit, truncated is true and truncation_note explains how to retrieve the rest. Download URLs are time-limited (typically 1 hour) — use the returned file_id with download_file to get a fresh URL at download time. When CANVAS_PSEUDONYMIZE_STUDENTS is enabled, user_name is a stable per-course pseudonym (e.g. "Student 1"); user_id (the raw numeric Canvas ID) is always returned and works as a stable per-student folder key. |
| list_submissions_awaiting_gradingA | Lists all submissions in a course that still need a human grade, sorted oldest-waiting first. Surfaces two categories:
Returns a triage list grouped by assignment or Classic Quiz, with per-submission details: student identity, workflow state, submitted_at, and whether the submission has pending manual-grading questions. Parameters:
Known limitations:
|
| list_rubricsA | List every rubric defined in a course, returning each rubric's title, points_possible, and criteria/ratings. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use get_rubric to fetch one rubric by ID once you have it, get_rubric_assessment for a specific student's completed assessment rather than the rubric definition, or create_rubric to add a new one. Requires the manage_rubrics permission in the course, so most students cannot call this. |
| get_rubricA | Get a single rubric's definition (title, points_possible, criteria, and rating levels) by ID. Use list_rubrics to find the rubric_id for a course first. Pass include=["assignment_associations"] to also retrieve the rubric association IDs that submit_rubric_assessment needs, or include=["assessments"|"graded_assessments"|"peer_assessments"] for assessor_id-only assessment summaries (no assessor name is returned). This returns the rubric's structure, not any one student's completed assessment — use get_rubric_assessment for that. Requires the manage_rubrics permission in the course, so most students cannot call this. |
| get_rubric_assessmentA | Get one student's submission for an assignment with the Canvas rubric_assessment attached, keyed by criterion_id (rating_id, comments, points per criterion) — this does not carry the assessor's name or any grader identity. This is the same full submission object (score, grade, workflow_state, submitted_at) that get_submission returns, requested here with |
| submit_rubric_assessmentC | Submit a rubric assessment with scores and comments for each criterion. |
| create_rubricA | Create a new rubric in a course with criteria and rating levels. Optionally link it to an assignment immediately. Returns { rubric, rubric_association? }; when an assignment association was requested, rubric_association.id is the association_id that submit_rubric_assessment takes. |
| attach_rubricA | Attach an existing course rubric to an assignment, so one rubric can be shared across many assignments instead of creating a duplicate per assignment with create_rubric. Returns the new rubric association. |
| delete_rubricA | Permanently delete a rubric from a course, removing it from every assignment it is attached to. Returns the deleted rubric. |
| list_quizzesA | List every quiz row in a course, including the New Quiz stub Canvas mixes into the same list (quiz_type: quizzes.next, with no question or submission detail of its own). Use quiz_type to tell Classic Quizzes (assignment, practice_quiz, graded_survey, survey) apart from New Quizzes, and list_new_quiz_items for a New Quiz's actual questions. Returns each quiz's title, quiz_type, points_possible, question_count, due_at and published state. Use get_quiz to fetch one quiz by ID, list_quiz_questions for its fixed questions, and list_quiz_submissions for student attempts. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. |
| get_quizA | Get one quiz by ID, found with list_quizzes. If the ID belongs to a New Quiz, Canvas returns only its stub row (quiz_type: quizzes.next) — use list_new_quiz_items for the actual question content. Returns title, quiz_type, points_possible, question_count, due_at, published state, and assignment_id (the graded assignment Canvas created for this quiz; null for an ungraded survey or practice quiz). Use list_quiz_questions for a Classic quiz's fixed questions and list_quiz_submissions for student attempts. |
| list_quiz_submissionsA | List every submission (one row per student's attempt history) for a Classic quiz, including each submission's score, kept_score, workflow_state, and any extra_time / extra_attempts accommodation Canvas has recorded for that student. Find the quiz_id with list_quizzes or get_quiz. To see a submission's actual answers, use get_quiz_submission_answers for an in-progress attempt or get_quiz_question_responses for a submitted one; to change a score use score_quiz_question. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. |
| list_quiz_questionsA | List the fixed questions defined on a Classic quiz — id, position, question_text, question_type, points_possible, and answers — in quiz order. This is the quiz's static question list only: it does not include the generated questions Canvas serves per attempt when a question-bank draw is configured, and it carries no student answer data. Find the quiz_id with list_quizzes or get_quiz. Use get_quiz_question_responses to see what each student was actually served and answered, including bank-drawn questions, and score_quiz_question to grade an answer. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. |
| get_quiz_submission_answersA | Get a quiz submission's state for an IN-PROGRESS (untaken) attempt, including the student's live answer and flag per question. For a SUBMITTED attempt (complete or pending_review), Canvas never returns the answer value or a real flag state through this endpoint — only grading state (correct) is available here. To review a submitted attempt's actual answer text, use get_quiz_question_responses instead. |
| score_quiz_questionA | Set the score and an optional feedback comment for one question in one student's Classic quiz submission, overwriting any existing score for that question on the chosen attempt — it replaces the question's recorded score rather than adding to it, so calling again with the same score and comment leaves the submission unchanged. Omit attempt to score the latest attempt. Find submission_id with list_quiz_submissions and question_id with list_quiz_questions or get_quiz_question_responses. Returns { success: true }; Canvas does not hand back the updated submission to this endpoint. Requires grading permission in the course. |
| get_quiz_submission_eventsA | Get the event log for a Classic Quiz submission in chronological order. Events include session_started, question_answered, question_flagged, page_blurred, and page_focused. Use this to understand the timeline of a student's attempt. Classic Quizzes only — New Quizzes does not expose event logs via the Canvas REST API. Events are scoped to a single submission; Canvas enforces access permissions (instructors and the submitting student only). Do not use event logs as the sole basis for academic-integrity conclusions; present them with context. |
| delete_quizA | Permanently delete a Classic quiz from a course, including its questions and every student submission. Classic Quizzes only; use delete_new_quiz for a New Quiz (LTI). |
| delete_quiz_questionA | Permanently delete a single question from a Classic quiz. Classic Quizzes only; use delete_new_quiz_item for a New Quiz item. |
| create_new_quizA | Create a New Quiz (LTI) in a Canvas course. Returns the created quiz with its id, assignment_id, and current field values. New Quizzes is Canvas's current quiz engine; there is no tool here to create a Classic quiz — list_quizzes, get_quiz, and delete_quiz only read and delete that older type. After creating, add questions with create_new_quiz_item, change title, dates, or points with update_new_quiz, and remove the quiz with delete_new_quiz. Each call creates another quiz (not idempotent), so check list_quizzes before retrying. quiz_settings covers session behavior (calculator, shuffle, time limit, access code, one-at-a-time, and multiple_attempts); its multiple_attempts sub-object is replaced as a whole by Canvas, so a later update_new_quiz call must repeat every multiple_attempts sub-field you want to keep. IP-address access filtering and result_view_settings are not supported by this tool. Requires permission to manage quizzes in the course. |
| update_new_quizA | Update an existing New Quiz (LTI) in a Canvas course, found by its assignment_id (from list_assignments or get_assignment, filtered on is_quiz_lti_assignment, or from create_new_quiz — not a Classic Quiz ID). Only the fields you pass change; omitted fields keep their current value, so a repeated call with the same payload leaves the quiz unchanged. Pass null for due_at, unlock_at, or lock_at to clear that date. Returns the updated quiz (id, title, points_possible, due_at, unlock_at, lock_at, published, assignment_id). Use update_new_quiz_item to change an individual question instead of the quiz shell, and delete_new_quiz to remove the whole quiz. quiz_settings's flat fields (calculator, shuffle, time limit, access code, one-at-a-time) each change independently, same as the rest of this call, but its multiple_attempts sub-object is replaced as a whole by Canvas: passing { multiple_attempts: { max_attempts: 3 } } clears every other multiple_attempts sub-field (which score to keep, the cooling period, …) instead of leaving them as they were, so repeat every sub-field you want kept. IP-address access filtering and result_view_settings are not supported by this tool. Requires permission to manage quizzes in the course. |
| delete_new_quizA | Delete a New Quiz (LTI) from a Canvas course. This action is permanent. Use assignment_id (not quiz_id). |
| list_new_quiz_itemsA | List every item (question or stimulus) in a New Quiz (LTI), in quiz order, returning each item's id, position, points_possible, entry_type, and full entry body — including interaction_data and scoring_data, so the correct answer is visible in the result. Find the assignment_id with list_assignments or get_assignment, filtered on is_quiz_lti_assignment (not a Classic Quiz ID). Use get_new_quiz_item to refetch a single item by id, create_new_quiz_item to add one, update_new_quiz_item to change one, and delete_new_quiz_item to remove one. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. |
| get_new_quiz_itemA | Get one item (question or stimulus) from a New Quiz (LTI) by its item_id, returning its position, points_possible, entry_type, and full entry body — including interaction_data and scoring_data, so the response reveals the correct answer. Find item_id with list_new_quiz_items, which also lists every item at once; use this tool only to refetch one item, such as right after create_new_quiz_item or update_new_quiz_item. assignment_id identifies the New Quiz (from list_assignments or get_assignment, filtered on is_quiz_lti_assignment), not a Classic Quiz ID. |
| create_new_quiz_itemA | Create one item (question) in a New Quiz (LTI). Returns the created item with its item_id, position, points_possible, and full entry body, including scoring_data. Supports 8 types: choice (one correct answer), multi-answer (select all that apply), true-false, essay, matching, numeric, rich-fill-blank (fill in the blank, with typed, dropdown, or word-bank blanks), and ordering (choices listed top-to-bottom in the correct sequence; Canvas shuffles their displayed order for the student). Each call adds another item (not idempotent), so check list_new_quiz_items before retrying a failed or uncertain create. Use update_new_quiz_item to change an existing item, delete_new_quiz_item to remove one, and create_new_quiz to make the quiz first. An item has no publish setting of its own; students see it when the quiz itself is published (update_new_quiz). assignment_id identifies the New Quiz (from list_assignments or get_assignment, filtered on is_quiz_lti_assignment), not a Classic Quiz ID. Canvas may rate-limit rapid creates, so call serially and pause between batches of about 50. Requires permission to manage quizzes in the course. |
| update_new_quiz_itemA | Update one existing item (question) in a New Quiz (LTI) by its item_id. Returns the updated item. Only the parts you pass are sent (position, points_possible, or item). When item is given, the whole item body (type, stem, choices, and answer) is rebuilt from it and sent, so pass the complete item, not only the changed field. It takes the same 8 types as create_new_quiz_item. Find item_id with list_new_quiz_items or get_new_quiz_item. Use create_new_quiz_item to add an item, delete_new_quiz_item to remove one, and update_new_quiz for quiz-level fields. assignment_id identifies the New Quiz (from list_assignments or get_assignment, filtered on is_quiz_lti_assignment), not a Classic Quiz ID. Canvas may rate-limit rapid updates, so call serially. Requires permission to manage quizzes in the course. |
| delete_new_quiz_itemA | Permanently delete one item (question or stimulus) from a New Quiz (LTI) by its item_id. This is irreversible — there is no undo and no tool to restore a deleted item. Returns { success: true }; Canvas does not hand back the deleted item. Find item_id with list_new_quiz_items or get_new_quiz_item. Use delete_new_quiz instead to remove the whole quiz, or update_new_quiz_item if you only need to change the item rather than remove it. assignment_id identifies the New Quiz (from list_assignments or get_assignment, filtered on is_quiz_lti_assignment), not a Classic Quiz ID. Requires permission to manage quizzes in the course. |
| get_quiz_question_responsesA | Review every student's answer to one or all questions in a Classic Quiz, pivoted by question instead of by student — for grading essay/short-answer/file-upload questions consistently across a class instead of paging through SpeedGrader one student at a time. Classic Quizzes only (quiz_type: assignment, practice_quiz, graded_survey, survey) — New Quizzes exposes responses through a different API. Omit question_id to get every question; provide it to scope to one. Each question reports needs_manual_grading (true for essay and file-upload questions) and points_possible. Questions drawn from a question bank are included: Canvas stores each draw as a generated question that the quiz's question list omits, so they are resolved from the students' own attempts, listed after the quiz's fixed questions, and report position: null. Each response reports the raw Canvas correctness value plus a derived scoring_state (correct / incorrect / partial / not_scored / awaiting_manual_grading / graded / unscored) so "undefined" is never read as an answer. Scans one Canvas API call per completed or pending-review submission, plus one per attempt needed to resolve bank-drawn questions, plus one paginated call to fetch every student's submitted answer text for the quiz (skipped, with answer_text_available: false and a reason, when the quiz has no assignment, is an anonymous survey, or the fetch fails). A failed per-submission answers fetch is recorded in submissions_failed, and a response whose question cannot be resolved is counted in unmatched_response_count and unmatched_question_ids, rather than aborting the whole call. When CANVAS_PSEUDONYMIZE_STUDENTS is enabled, student names are replaced with stable pseudonyms; essay/short-answer prose is student-authored text and may itself contain a real name, which pseudonymization of structured fields cannot strip. |
| list_filesA | List every file in a course's Files area, returning metadata only — name, size, content type, folder_id, and the Canvas-hosted download URL — not the file's content. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use download_file to fetch a file's actual content, get_file to refetch a single file's metadata by ID, list_folders for the folder tree these files sit in, and find_duplicate_files to spot same-name-and-size copies left over from course copies. |
| list_foldersA | List every folder in a course's Files area, including each folder's name, full path, parent_folder_id, and file/subfolder counts, but not the files or subfolders inside each one. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use list_files to see the files inside a folder, and upload_file's |
| get_fileA | Get metadata for a single file by ID, including download URL. |
| upload_fileA | Upload a new file to a course's Files area from base64-encoded content, and return the created file object (id, display_name, size, content_type, download url). Each call performs a new upload; check list_files first if you want to avoid creating a duplicate, and use delete_file to remove a file afterward. Canvas handles the upload as a multi-step hand-off to its storage backend (S3 or local Canvas storage), transparent to the caller. |
| delete_fileA | Permanently delete a file by ID, and return the deleted file object (its last known metadata) — the content is gone and there is no undelete. Use upload_file to put a replacement back afterward; Canvas assigns the new file a different ID rather than reusing the deleted one. Requires permission to manage files in the course. |
| download_fileA | Download the content of a Canvas file by ID. Text files (plain text, HTML, JSON, XML, JavaScript) are returned as readable text. Binary files (images, PDFs, etc.) are returned as base64-encoded data. Files larger than 10 MB are refused. |
| find_duplicate_filesA | Find duplicate files in a course's Files area — copies with the same name and size, typically left behind by repeated course copies. Each duplicate gets flagged separately by accessibility checkers, so this surfaces them for cleanup with the existing delete_file tool. Groups by display name + size (Canvas file listings carry no content hash), so same-name files of different sizes are not considered duplicates. |
| list_gradebook_history_daysB | List the dates in a course gradebook history that contain grading activity, grouped by grader and assignment. |
| get_gradebook_history_dayA | Get the graders and assignment IDs that had gradebook activity on a specific course date. |
| list_gradebook_history_submissionsA | List versioned submission history for one grader and assignment on a specific gradebook history date. |
| get_gradebook_history_feedA | Get the paginated gradebook history feed for a course, optionally filtered by assignment or user and optionally sorted oldest-first. |
| list_studentsA | List every student enrolled in a course (enrollment_type=student only), returning Canvas user objects (id, name, email, login_id) without grades or enrollment details. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use list_course_users for every role in the course (teachers, TAs, observers) or to filter users by enrollment_state, and list_course_enrollments when you need the enrollment/grade objects themselves (score, grade, enrollment workflow_state) rather than user profile fields. In pseudonymized mode every returned user's name and email are anonymized, since this endpoint carries no enrollment data for role classification to tell staff apart. |
| get_userA | Get a single Canvas user by numeric ID, returning the full Canvas user object (name, email, login_id, time_zone, bio, pronouns) when the caller is permitted to see it. Use get_profile instead when the target is the caller's own account, search_users to find a user when you only know their name, login, or email in an account, or list_course_users to see every user enrolled in a specific course. Because a bare ID lookup carries no enrollment data, pseudonymized mode cannot tell staff from students here and conservatively anonymizes the name and email on every call; list_course_users only keeps a real name when it is also called with |
| get_profileA | Get the profile of the currently authenticated user. |
| search_usersA | Search for users in a single Canvas account by name, login, or email, returning matching Canvas user objects. Use |
| list_course_usersA | List users in a course with optional Canvas filters. Use |
| list_groupsB | List all groups in a course. |
| list_group_membersC | List all members of a group. |
| list_group_categoriesA | List the group categories (group sets) in a course. A group assignment points at a category through its group_category_id, and create_group needs a category ID, so use this to find one. |
| create_group_categoryB | Create a new, empty group category (group set) in a course. |
| create_groupA | Create a group inside a group category. This is addressed by group_category_id, not by course ID: find the category with list_group_categories. The new group has no members; add them with add_group_member. |
| delete_groupA | Permanently delete a group and remove all of its members. The students stay enrolled in the course and the group category remains. Creating a group again does not restore the same group. |
| add_group_memberA | Add a user to a group. Returns the membership Canvas reports; if the user is already a member, Canvas returns the existing membership. remove_group_member removes this membership; it does not restore any other group membership Canvas changed. |
| remove_group_memberA | Remove a user from a group. The user stays enrolled in the course. Reverse with add_group_member. |
| list_enrollmentsA | List every enrollment the authenticated user holds across all of their Canvas courses — the caller's own enrollments only. Use |
| list_course_enrollmentsA | List enrollments within a specific course with Canvas filters. Use |
| enroll_userA | Enroll a user in a course with a given role (StudentEnrollment, TeacherEnrollment, TaEnrollment, ObserverEnrollment, or DesignerEnrollment) and return the created enrollment object, including its |
| remove_enrollmentA | Remove or conclude an enrollment from a course. The 'delete' task is permanent; 'conclude' and 'deactivate' are reversible. |
| list_discussionsA | List discussion topics in a course, returning id, title, message, posted_at, discussion_type, published, and is_announcement for each topic — replies are not included. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use get_discussion to fetch one topic in full detail including due/available dates, post_discussion_entry to reply, and list_announcements to see only announcements. |
| get_discussionA | Get a single discussion topic in a course by ID, returning its title, message, posted_at, discussion_type, published state, and is_announcement, plus due/available dates via Canvas's all_dates include. Find topic_id with list_discussions. Course-scoped only — use get_group_discussion for a topic that belongs to a group instead of a course. |
| list_group_discussionsA | List discussion topics in a group, returning id, title, message, posted_at, discussion_type, published, and is_announcement for each topic — replies are not included. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use get_group_discussion to fetch one topic in full detail including due/available dates, and list_discussions for the course-scoped equivalent; there is no group-scoped counterpart to post_discussion_entry or list_announcements. |
| get_group_discussionA | Get a single discussion topic in a group by ID, returning its title, message, posted_at, discussion_type, published state, and is_announcement, plus due/available dates via Canvas's all_dates include. Find topic_id with list_group_discussions. Group-scoped only — use get_discussion for a topic that belongs to a course instead of a group; there is no group-scoped counterpart to post_discussion_entry, so this server cannot post a reply to a group topic yet. |
| list_announcementsA | List announcements in a course, returning id, title, message, and posted_at for each one. Canvas serves this from the same discussion_topics index as list_discussions, filtered to topics marked is_announcement via the only_announcements query parameter. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use create_discussion with is_announcement: true to post a new announcement, and update_discussion to edit one afterward. |
| post_discussion_entryA | Post a new entry (reply) to a discussion topic in a course, and return the created entry (id, user_id, message, created_at). Not idempotent: each call adds another reply, Canvas does not deduplicate repeated calls. Works even on a topic Canvas has made anonymous, where get_discussion itself 404s — use list_discussions to confirm the topic exists and find its topic_id. Requires the caller to have an active enrollment in the course with permission to post to the forum, which Canvas grants to students, TAs and instructors by default unless an admin has restricted it. |
| create_discussionA | Create a new discussion topic in a course, and return the created topic (id, title, message, discussion_type, published, is_announcement, posted_at). Not idempotent: each call creates another topic — Canvas does not deduplicate by title, so check list_discussions first to avoid creating a duplicate. Setting is_announcement: true asks Canvas to create an announcement, but Canvas silently creates a plain discussion topic instead (HTTP 200, no error) if the caller lacks announcement-create permission in the course — this tool then throws instead of reporting success, naming the topic ID so you can check it with list_discussions or get_discussion. Use update_discussion to change an existing topic afterward, delete_discussion to remove one, and post_discussion_entry to reply to a topic instead of creating a new one. Requires instructor/TA permission to manage discussions in the course. |
| update_discussionA | Update an existing discussion topic in a course — title, message, published state, require_initial_post, delayed_post_at, or is_announcement — and return the updated topic; only the fields you pass are changed, the rest keep their current value. Course-scoped only: there is no update tool for group discussions, though list_group_discussions and get_group_discussion can still read them. Setting is_announcement: true asks Canvas to turn the topic into an announcement, but Canvas silently keeps it a plain discussion topic (HTTP 200, no error) if the caller lacks announcement-create permission in the course — this tool then throws instead of reporting success, naming the topic ID so you can check it with list_discussions or get_discussion. Use create_discussion to make a new topic, delete_discussion to remove one, list_announcements to see existing announcements, and post_discussion_entry to reply instead of editing the topic itself. Requires instructor/TA permission to manage discussions in the course. |
| delete_discussionA | Delete a discussion topic from a course. This action is permanent. |
| list_modulesA | List all modules in a course, including each module's name, position, publication state, unlock date and item count, but not the items inside. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use |
| get_moduleA | Get a single module by its Canvas ID, including its name, position, publication state, unlock date and item count, but not the item list itself. Find the module_id via |
| list_module_itemsA | List every item in one module — Assignment, Page, Quiz, File, Discussion, ExternalUrl, ExternalTool or SubHeader — in module order, including each item's |
| get_course_structureA | Return the full module → items tree for a course in a single call, with summary stats. Avoids N+1 round-trips when an agent needs to reason over the whole course shape. |
| view_course_structureA | Interactive tree view of a course's modules and items. Returns the same payload as |
| create_moduleA | Create a new module in a course. Returns the created module, including its new Canvas ID. Each call creates a separate module — calling it twice with the same name makes two modules, not one — so check |
| update_moduleA | Update an existing module's name, position or published state, and return the updated module object. Only the fields you pass are changed — anything you omit keeps its current value. Setting |
| delete_moduleA | Permanently delete a module from a course, including its ordered list of module items. Assignments, pages, quizzes, files and discussions that the items link to are stored separately in the course and this call does not delete them, but ExternalUrl, ExternalTool and SubHeader items exist only inside the module and go with it. There is no single inverse: rebuilding the module means create_module plus create_module_item for each item. |
| create_module_itemA | Add an item to a module: Assignment, Page, Quiz, File, Discussion, ExternalUrl, ExternalTool or SubHeader. Returns the created module item, including its new Canvas ID. Each call adds a new item — calling it twice with the same title adds two items, not one. Which identifying field to pass depends on |
| update_module_itemA | Edit an existing module item in place: rename it, repoint an ExternalUrl/ExternalTool item, reposition or re-indent it, publish/unpublish it, or move it to another module. ExternalUrl items exist only as module items, so a stale link carried in by a course copy can only be fixed here. |
| delete_module_itemA | Remove an item from a module. For ExternalUrl, ExternalTool and SubHeader items the item is the content, so this deletes it outright; for Assignment, Page, Quiz, File and Discussion items it only unlinks the item and the underlying content survives. Re-add with create_module_item. |
| list_pagesA | List every wiki page in a course, returning page stubs — title, url slug, published state and editing_roles — without the HTML body; the paginated list endpoint omits body entirely. Use get_page to fetch one page's full body by its url slug, or search_course_content to search page content across the whole course. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. |
| get_pageA | Get one wiki page by its page_url slug — not a numeric ID — obtained from list_pages. Returns the page's title, published state, editing_roles and full HTML body, unlike the list endpoint's body-less stubs. Use list_pages to discover a course's pages and find a page_url, and update_page to edit this page's title, body, published state or editing_roles afterward. |
| create_pageA | Create a new wiki page in a course with a title and optional HTML body, published state and editing_roles, and return the created page — including its url slug, used as page_url by get_page, update_page and delete_page. Not idempotent: each call creates another page; Canvas does not deduplicate by title, so check list_pages first to avoid creating a duplicate. Use update_page to edit an existing page instead of creating a new one, and create_module_item's page_url parameter (with type Page) to place this page inside a module. Requires permission to manage wiki content in the course. |
| update_pageA | Update an existing wiki page's title, body, published state or editing_roles. Only the fields you pass are sent to Canvas; omitted fields are left unchanged. body is not merged — it replaces the entire HTML body, so read the current content with get_page first and send back the full edited body, not just the changed part. Returns the updated page. Idempotent: calling it again with the same fields produces the same resulting page. Use create_page to make a new page instead, delete_page to remove this one, and update_course's syllabus_body parameter to edit the course syllabus, which is not a wiki page editable here. Requires permission to manage wiki content in the course. |
| delete_pageA | Delete a wiki page from a course. This action is permanent. |
| list_calendar_eventsA | List calendar events for a course, unbounded by the ~1-week/20-item caps that |
| create_calendar_eventA | Create a new calendar event and return the created event object, including its |
| update_calendar_eventA | Update an existing calendar event. Only provided fields are changed. |
| list_conversationsA | List the authenticated user's inbox: every non-archived conversation, both read and unread, newest first, returning each one's id, subject, last_message, last_message_at, message_count, and participants (id, name) — no message bodies; use get_conversation for the full thread. There is no scope filter here, so starred-only, archived, sent-only, or unread-only views aren't available. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use get_conversation_unread_count for just the unread total instead of the whole inbox. |
| get_conversationA | Get one conversation's full message thread by id, returning its subject, participants, and every message (id, body, author_id, created_at) — not just the last_message summary list_conversations returns. Canvas marks any unread messages in this thread as read as a side effect of calling this, so re-reading a thread changes its unread state. Find the conversation_id with list_conversations. Use get_conversation_unread_count to check the inbox-wide unread total without marking anything read. |
| get_conversation_unread_countA | Get the number of unread conversations for the authenticated user as a single integer — not the conversations themselves, and not a count of unread messages within them. Use list_conversations to see which conversations are unread, or get_conversation to open one and mark its messages read. |
| send_conversationA | Send a new message and return the created conversation object(s) (id, subject, participants) — one per recipient. With more than one entry in recipients, this creates a separate private conversation with each recipient rather than one shared group thread: each recipient sees only their own copy, and nobody sees who else received it. Every call sends again — there is no dedup against an already-sent message with the same subject and body. recipients must be real Canvas user ids as strings; list_course_users or search_users can look those up first. Requires the authenticated user to have permission to message every recipient (course messaging rules and any inbox restrictions Canvas enforces). Use list_conversations and get_conversation to review what was sent. |
| list_peer_reviewsA | List every peer review assigned on an assignment, across every submission, returning each review's id, assessor_id (the reviewer), user_id (the reviewee whose submission is being reviewed), asset_id, and workflow_state ('assigned' or 'completed'). Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Pass submission_id to scope the results to the reviews assigned to that one submission instead of the whole assignment — the same result get_submission_peer_reviews returns, kept here as a shortcut. Omit it to see every review across the assignment. Use create_peer_review to assign a new reviewer, and delete_peer_review to remove one. |
| get_submission_peer_reviewsA | List the peer reviews assigned to one submission within an assignment — a single submission can have more than one assigned reviewer — returning each review's id, assessor_id (the reviewer), user_id (the reviewee), asset_id, and workflow_state ('assigned' or 'completed'). Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use list_peer_reviews instead to see every review assigned across the whole assignment rather than one submission, create_peer_review to assign another reviewer to this submission, and delete_peer_review to remove one. |
| create_peer_reviewA | Assign a Canvas user as a peer reviewer for one submission, and return the created peer review object (id, assessor_id, user_id, asset_id, workflow_state). The user_id parameter you pass is the reviewer being assigned; in the returned object assessor_id holds that same reviewer, while the response's own user_id field instead identifies the submission owner (the reviewee) — the two user_id values are not the same person. The new review starts in workflow_state "assigned". submission_id must already exist on this assignment. Use list_peer_reviews to see every review assigned on the whole assignment, or get_submission_peer_reviews to see only the reviews assigned to one submission, before assigning another reviewer; use delete_peer_review to unassign one. Requires instructor/TA permission in the course. |
| delete_peer_reviewA | Remove a peer-review assignment — identified by its assessor_id/user_id pairing — from one submission, unassigning that reviewer; the submission and the assignment itself are untouched, only the peer-review relationship goes away. Returns a confirmation message; Canvas's own response body is discarded. This is a reversible relationship removal, not an irreversible content delete: re-create the assignment with create_peer_review, though the new review gets a new id and workflow_state starts over at "assigned". Find the reviewer's user_id to remove with list_peer_reviews or get_submission_peer_reviews. Requires instructor/TA permission in the course. |
| get_accountA | Get a single Canvas account by ID, including its name, parent and root account IDs, UUID, default storage quotas, and workflow state. Find the account_id via |
| list_accountsA | List all accounts accessible to the authenticated user. |
| list_sub_accountsA | List the direct child accounts nested under a given Canvas account — one level deep, not grandchildren or deeper descendants. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use |
| list_account_coursesA | List every course in a Canvas account, optionally filtered by |
| list_account_usersA | List every user in a Canvas account — every role the account contains, not only students — optionally filtered by |
| get_account_reportsA | List the report types a Canvas account supports — csv/grade exports, SIS imports, and institution-specific types — each with its report key, title, expected parameters, and the most recent |
| list_account_notificationsA | List active global institution-wide announcements for the current user (maintenance windows, term deadlines, policy notices). |
| view_account_notificationsA | Interactive panel of active institution-wide announcements. Returns the same payload as |
| search_course_contentA | Search for content within a course. Searches pages, assignments, discussions, and announcements by keyword. |
| get_course_analyticsA | Get course-level activity analytics. Returns daily page view and participation counts. |
| get_student_analyticsA | Get per-student activity analytics for a course. Returns page views, participations, and submission timeline for a specific student. |
| get_course_activity_streamA | Get a summary of recent activity in a course. Returns counts of recent events grouped by type (submissions, discussions, announcements, etc.). |
| get_assignment_analyticsA | Get score distribution analytics for assignments in a course. Returns statistical summary (min, max, median, first/third quartile), submission count, and tardiness breakdown (on_time, late, missing) for each assignment. Provide assignment_id to scope to one assignment; omit to return analytics for all assignments in the course. |
| get_root_outcome_groupA | Get the root outcome group for an account or course context, the entry point into the outcome tree. Returns the top-level outcome group (id, title, subgroups_url, outcomes_url); walk from there with list_outcome_group_subgroups for its child groups and list_outcome_group_outcomes for outcomes linked directly under a group, or use list_outcome_groups for a flat listing of every group in the context instead of walking the tree. |
| list_outcome_groupsA | List every outcome group in an account or course context as a flat array, not a tree. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use get_root_outcome_group plus list_outcome_group_subgroups to walk the hierarchy instead, or get_outcome_group to fetch one group's details by ID. |
| list_outcome_group_linksA | List every outcome link in an account or course context — the many-to-many join between outcome groups and the outcomes they contain, read from the context root, not one specific group. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Each link nests its outcome_group and outcome (full detail when outcome_style="full" / outcome_group_style="full", abbreviated otherwise); use list_outcome_group_outcomes instead to list only the outcomes linked directly under one specific outcome_group_id. |
| get_outcome_groupA | Get the full details for one outcome group by outcome_group_id within an account or course context, including its subgroups_url and outcomes_url. The ID comes from list_outcome_groups, list_outcome_group_subgroups, or get_root_outcome_group; use list_outcome_group_outcomes to list the outcomes linked under this group and list_outcome_group_subgroups to list this group's child groups. |
| list_outcome_group_outcomesA | List the outcomes linked directly under one outcome group (outcome_group_id), not its subgroups' outcomes. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Each link nests the outcome (full detail when outcome_style="full", abbreviated otherwise); use list_outcome_group_subgroups to descend into child groups first, or get_outcome for one outcome's full detail by outcome_id. |
| list_outcome_group_subgroupsA | List the immediate child outcome groups under one outcome group (outcome_group_id) — one level of the tree, not a recursive walk. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Call this again with each returned group's id to descend further, or use list_outcome_group_outcomes on the same outcome_group_id to list outcomes linked directly under it instead of its child groups. |
| get_outcomeA | Get the full details for one learning outcome by outcome_id, including its rating criteria, mastery_points, and calculation_method. The outcome_id comes from list_outcome_group_outcomes, list_outcome_group_links, or get_outcome_results' / get_outcome_rollups' linked.outcomes; get_outcome_alignments lists all alignments in the course (not scoped to one outcome) — cross-reference via get_outcome_results instead to tie an alignment to this outcome_id. |
| get_outcome_alignmentsA | Get the assignments aligned to outcomes in a course, optionally filtered to one student_id or assignment_id. Returns each alignment's assignment_id and title, but not the outcome_id it maps to. get_outcome_results nests the same alignment objects under linked.alignments, but ties an alignment to an outcome via each outcome_results[] entry's links.alignment and links.learning_outcome, not from linked.alignments alone. Use get_outcome_contributing_scores to see the assignment scores that produced an outcome's results instead of just the links. |
| get_outcome_resultsA | Get raw per-student, per-alignment outcome results for a course (one score per assessed alignment, not aggregated), optionally filtered by user_ids, outcome_ids, and include_hidden. Set include_alignments to nest the matching alignments under linked.alignments. When CANVAS_PSEUDONYMIZE_STUDENTS is enabled, linked.users entries are anonymized; use resolve_pseudonym to map one back to a real user. Use get_outcome_rollups instead for aggregated scores per student and outcome, or get_outcome_contributing_scores for the assignment or quiz scores behind one outcome. |
| get_outcome_rollupsA | Get aggregated outcome rollups for a course — one score per student per outcome, or, with aggregate="course", a single course-level mean or median — optionally filtered by user_ids and outcome_ids and sorted by student or by one outcome's score. Set include_courses to nest course details under linked.courses. When CANVAS_PSEUDONYMIZE_STUDENTS is enabled, linked.users entries are anonymized; use resolve_pseudonym to map one back to a real user. Use get_outcome_results instead for the raw per-alignment scores behind a rollup, or get_outcome_mastery_distribution for a mastery-level histogram across students. |
| get_outcome_contributing_scoresA | Get the assignment or quiz scores that contributed to one outcome_id's results for one or more students in a course, optionally restricted to assignment alignments only or including unpublished assignments. Use get_outcome_results instead for the final per-alignment outcome score rather than the scores that fed it, or get_outcome_alignments to list all alignments in the course (not scoped to this outcome) without their scores. |
| get_outcome_mastery_distributionA | Get a mastery-level histogram for outcomes in a course — how many students fall into each rating band — optionally filtered by outcome_ids and student_ids and excluding missing user rollups or missing outcome results. Set include_alignment_distributions to also break down scores by contributing alignment. Use get_outcome_rollups instead for each student's individual aggregated score, or get_outcome_results for the raw per-alignment scores. |
| get_my_coursesA | List active courses for the authenticated student. |
| get_my_gradesA | Get grade data for the authenticated student. If course_id is omitted, returns grades across all enrolled courses. |
| get_my_submissionsB | List all submissions for the authenticated student in a course. |
| get_my_upcoming_assignmentsA | List upcoming assignment events for the authenticated student. Canvas caps this endpoint at roughly the next 1 week and at most 20 events server-side — neither limit is adjustable, and results silently stop there even if more assignments fall later. For a longer or specific date range, use |
| get_my_submission_feedbackA | List the authenticated student's own submissions that carry feedback comments from an instructor or a peer reviewer — comments left by the student themselves do not count as feedback and submissions with no non-self comments are omitted. Omit |
| get_my_activity_stream_summaryA | Count unread and total items in the authenticated student's cross-course activity stream, grouped by Canvas item type (e.g. DiscussionTopic, Announcement, Submission, Conversation). No item content — counts only. A good first call in a daily workflow to check "is there anything to look at?" before fetching the full stream. |
| get_my_activity_streamA | The authenticated student's cross-course activity stream: new discussion posts, announcements, conversation messages, graded submissions, peer-review requests and conference invitations from every course at once, newest first. Four caveats, none of them visible in the response: (1) RECENT ACTIVITY ONLY — typically the last ~4 weeks; the retention window is a per-Canvas-instance setting and cannot be read through the API, so "nothing found" is not evidence that nothing happened. (2) Each item's |
| list_my_planner_itemsA | The authenticated student's planner: assignments, ungraded quizzes, planner notes, wiki pages, ungraded discussions, calendar events, peer reviews, sub-assignments and peer-review sub-assignments — everything with a due or to-do date, across every course and group at once. Strictly richer than get_todo_items, which covers only assignments needing submitting or grading. Four caveats: (1) start_date and end_date must be given TOGETHER or OMITTED TOGETHER — supplying only one makes Canvas silently default the other side to a ten-year window, so a half-specified range is rejected outright; omitting both resolves to Canvas's own ~2-week default, echoed back as the response's |
| get_my_course_requirementsA | What the authenticated student still has to DO in one course: a per-module requirement graph where every row names the Canvas endpoint and field its verdict came from. Richer than list_modules plus list_module_items, which return a raw |
| find_student_across_coursesA | Search the caller's teaching courses — active and, by default, concluded (past-term) ones — for a student by name, login, or email, and report every matching course with the student's enrollment state and last activity. Set |
| get_dashboard_cardsA | Get the current user's dashboard course cards with position, color, and image. |
| get_todo_itemsA | Get the current user's to-do items, including upcoming assignments and grading tasks. |
| get_upcoming_eventsA | Get the current user's upcoming calendar events and assignments. Canvas caps this endpoint at roughly the next 1 week and at most 20 events server-side — neither limit is adjustable, and results silently stop there even if more events fall later. For a longer or specific date range, use |
| get_missing_submissionsA | Get assignments with missing submissions for the current user. |
| list_submission_comments_needing_attentionA | List submissions where the most recent comment is from the student and has not been addressed by grading or a reply — i.e. comments the instructor has likely not seen. Returns a triage list, oldest-unaddressed first. Requires instructor/TA permissions in the course. |
| list_students_needing_attentionA | Report students who may need instructor attention based on inactivity, missing or late submissions, and low current score. Each finding lists the exact signals that fired and the thresholds used — this is a factual report, not a prediction. Requires instructor/TA permissions in the course. |
| create_content_exportA | Start a Canvas course content export (Common Cartridge / QTI / zip). Exports are asynchronous — this tool returns immediately with an export ID and initial workflow_state ("created"). Call get_content_export to poll progress and retrieve the time-limited download link when the export finishes. |
| get_content_exportA | Get the status of a content export. When workflow_state is "exported", attachment.url contains a time-limited download link — download it promptly, as the URL expires (re-fetch to get a fresh one). Returns attachment: null while still "created"/"exporting" or on "failed". |
| list_content_exportsB | List all content exports for a course (most recent first). |
| list_content_migrationsB | List all content migrations for a course (most recent first). |
| get_content_migrationA | Get the status of a single content migration. When workflow_state is "running", poll progress_url for live updates. When "completed", the migration is done. |
| list_content_migration_typesA | List available migration types (migrators) for a course. Returns migrator type keys such as course_copy_importer, common_cartridge_importer, zip_file_importer, qti_converter, moodle_converter. |
| get_migration_selective_dataA | Get the selective import tree for a migration — the list of content items available to selectively import. Only meaningful for migrations in the "waiting_for_select" state. |
| get_migration_asset_id_mappingA | Get the old-to-new asset ID mapping for a completed migration. Useful for resolving references to content that existed in the source course. |
| list_migration_issuesA | List issues encountered during a content migration. Each issue has a type (todo, warning, or error) and a description. |
| create_content_migrationA | Start a content migration (course copy, Common Cartridge import, zip import, QTI conversion, or Moodle conversion). Migrations are asynchronous — this tool returns immediately with a migration ID and progress_url. Poll get_content_migration or progress_url to track completion. |
| list_grading_standardsA | List grading standards available in a course or account context. Provide either course_id (to see standards scoped to a course) or account_id (to see account-level standards, requires admin access). Returns an array of grading standard objects, each with an id, title, context, and grading_scheme array of { name, value } entries. |
| create_grading_standardA | Create a new grading standard (letter-to-percentage scheme) in a course or account context. Provide either course_id or account_id (account requires admin). scheme_entries is an array of { name, value } objects where value is the lower-bound percentage as a fraction 0–1 (e.g. { name: "A", value: 0.94 } means A ≥ 94%). Entries will be sorted descending by value before sending to Canvas. Canvas POST body key is grading_scheme_entry (singular); the returned object uses grading_scheme (plural). Returns the created grading standard object including its id — use that id with apply_grading_standard_to_course to activate it on a course. |
| apply_grading_standard_to_courseA | Apply an existing grading standard to a course so the gradebook uses it. Pass the grading_standard_id returned by create_grading_standard or list_grading_standards. Pass null for grading_standard_id to remove the current grading standard from the course. Returns the updated course object. |
| set_student_quiz_accommodationA | Apply extra time and/or extra attempts to a specific student across all Classic Quizzes in a course (or a specified subset). Fans out to the Canvas quiz extensions API for each quiz. New Quizzes (quiz_type quizzes.next) are skipped — use set_student_new_quiz_accommodation instead. Only applies to quizzes that exist at call time; re-run after creating new quizzes. Assignment due-date overrides are not handled here (separate fast-follow feature). Note: for courses with many quizzes this makes one Canvas API call per quiz. Partial failures are tolerated — a failure on one quiz does not abort the rest. Returns the standard fan-out envelope: separated applied[], skipped[] (each with a skip_reason), and failed[] (each with an error) arrays, a not_found list of any requested quiz_ids absent from the course, and a summary of counts. Provide user_id as the real Canvas user ID. If CANVAS_PSEUDONYMIZE_STUDENTS is enabled, call resolve_pseudonym first to obtain the real user_id from a pseudonym. |
| list_student_quiz_accommodationsA | List the current quiz accommodation (extra time and/or extra attempts) for a specific student across all Classic Quizzes in a course. Useful for auditing before or after calling set_student_quiz_accommodation. New Quizzes (quiz_type quizzes.next) are excluded. Reads extra_time / extra_attempts from each quiz's submission records (Canvas exposes no read endpoint for quiz extensions directly) — one Canvas API call per Classic Quiz, so it may be slow for courses with many quizzes. Errors from any quiz's read propagate immediately (no per-quiz error catching). Provide user_id as the real Canvas user ID. If CANVAS_PSEUDONYMIZE_STUDENTS is enabled, call resolve_pseudonym first. |
| set_student_new_quiz_accommodationA | Apply a time and/or attempts accommodation for a student across all New Quizzes in a course (course-level, single Canvas API call when no assignment_ids are given) or for a specified subset of New Quizzes (per-quiz fan-out when assignment_ids are given). New Quizzes use a time_multiplier (ratio, e.g. 1.5 for 1.5× time), not absolute minutes. For Classic Quizzes (quiz_type: assignment / practice_quiz / etc.) use set_student_quiz_accommodation instead. Partial per-quiz failures are tolerated — a failure on one quiz does not abort the rest. In per-quiz mode, fan-out is sequential (one Canvas API call per assignment ID, awaited in series). Canvas errors on the course-level path (no assignment_ids) propagate as a top-level error (no envelope). Returns a uniform envelope: scope ("course" or "per_quiz"), applied[], failed[], and summary. Provide user_id as the real Canvas user ID. If CANVAS_PSEUDONYMIZE_STUDENTS is enabled, call resolve_pseudonym first to obtain the real user_id from a pseudonym. |
| list_student_new_quiz_accommodationsA | Read the current course-level New Quizzes accommodation (time multiplier and/or extra attempts) for a specific student in a course. Useful for auditing before or after calling set_student_new_quiz_accommodation. Returns has_accommodation: false when no accommodation is set (Canvas 404 is treated as "no record", not an error). New Quizzes store a single course-level accommodation record per student; this is not per-quiz. For Classic Quizzes, use list_student_quiz_accommodations instead. Provide user_id as the real Canvas user ID. If CANVAS_PSEUDONYMIZE_STUDENTS is enabled, call resolve_pseudonym first. |
| list_assignment_overridesA | List all due-date / availability overrides for a specific assignment in a course. Returns overrides targeting individual students, sections, or groups. Useful for auditing before creating a new override — Canvas returns a 422 if a student-set override already exists for the same students on the same assignment. |
| create_assignment_overrideA | Create a due-date / availability override for a specific assignment, targeting a set of students, a course section, or a group. Exactly one of student_ids, course_section_id, or group_id must be provided. At least one date field (due_at, unlock_at, lock_at) should be provided; omit a date field to leave the corresponding date unchanged for the override target. Dates must be ISO 8601 strings (e.g. "2026-09-15T23:59:00Z"). Canvas returns a 422 if a student-set override already exists for the same students on this assignment — use list_assignment_overrides to audit first. Provide student_ids as real Canvas user IDs. If CANVAS_PSEUDONYMIZE_STUDENTS is enabled, call resolve_pseudonym first to resolve pseudonyms to real user IDs. |
| set_student_assignment_datesA | Fan a due-date / availability override for a specific student across all (or a filtered subset of) assignments in a course. Creates one student-set override per assignment via the Canvas assignment overrides API. Partial failures are tolerated — a failure on one assignment does not abort the rest. Note: for courses with many assignments this makes one Canvas API call per assignment. V1 is create-only: if an override for this student already exists on an assignment, Canvas returns a 422 and that assignment appears in the failed[] list. Use list_assignment_overrides to audit first. Dates must be ISO 8601 strings. To shift dates by a relative amount, first call list_assignments with include=overrides to retrieve current dates, compute absolute timestamps, then call this tool. Returns the standard fan-out envelope: separated applied[], skipped[] (unused in this create-only version, always empty), and failed[] (each with an error) arrays, a not_found list, and a summary of counts. Any assignment_ids that do not exist in the course are reported in not_found (they are neither applied nor failed). Provide user_id as the real Canvas user ID. If CANVAS_PSEUDONYMIZE_STUDENTS is enabled, call resolve_pseudonym first to obtain the real user_id from a pseudonym. |
| check_course_setupA | Run a factual course-readiness report that surfaces common configuration problems — assignments missing due dates, unpublished items students will not see, gradebook weighting gaps, graded assignments with no points, and published assignments still accepting submissions after their due date. Returns findings grouped by check with a plain-language detail per item. This is a config-health report only; it does not inspect student submissions or performance (see list_students_needing_attention / get_missing_submissions for those). Requires instructor permissions in the course. |
| explain_gradeA | Recomputes and explains the weighted course grade for a student, including assignment-group weights, drop_lowest / drop_highest / never_drop rules, per-group breakdowns (earned points, dropped assignments, weighted contributions), the mapped letter grade (via the course grading standard when present), and a reconciliation check against Canvas's posted current_score / final_score. Use this when you need to verify that Canvas's displayed grade matches the rules, or to explain to a student or instructor how their grade was calculated. Limitations:
|
| explain_grading_policyA | Explains the grading automation rules configured for a Canvas course:
Also returns a plain-language summary paragraph you can share with students or instructors. Note: the late/missing policy section requires instructor or admin permissions. Students receive the group-weighting and grading-scheme sections only, with a caveat noting what is unavailable. Use explain_grade to compute the actual weighted grade for a specific student. |
| project_gradeA | Projects the minimum score needed on remaining assignments to reach a target course grade. Given a target (as a percentage, e.g. 90, or a letter grade, e.g. "A") and the student's current scores, computes the minimum uniform percentage that must be earned on all remaining (not yet graded) assignments for the overall course grade to reach the target. Accounts for assignment-group weights, drop_lowest / drop_highest / never_drop rules, and the course grading scheme (for letter-grade targets and output letter mapping). Returns:
Limitations:
|
| audit_course_linksA | Scan a course's content (pages, assignments, syllabus, announcements, and optionally quizzes) for broken or outdated links and images. Returns structured findings: cross-course references (links that still point at a previous copy of the course — the canonical stale-copy failure after a course import) and empty/malformed URLs. Pass "quizzes" in |
| audit_course_accessibilityA | Scan a course's content (pages, assignments, syllabus, announcements, and optionally quizzes) for structurally-detectable WCAG 2.1 accessibility problems: images missing alt text or with low-quality (filename/generic) alt text, non-descriptive link text ("click here"), adjacent duplicate links, skipped/empty/overlong headings, and tables missing headers, header scope, or captions. Each finding carries a WCAG success criterion and a severity (error = unambiguous failure, advisory = needs human review). Structural checks only — no color-contrast checking (requires rendered theme CSS this tool cannot see) and no list-misuse detection in this version. Pass "quizzes" in |
| list_appointment_groupsA | List appointment groups (Canvas Scheduler sign-up slots) visible to the current user, returning each group's id, title, context_codes, workflow_state, and location — time slots, per-slot reservations, and participant counts are each left out unless you pass the matching include value. scope defaults to "reservable" (groups the user is eligible to sign up for; reserving a slot itself happens in the Canvas UI, not through this server) and can be set to "manageable" for the groups the user administers. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Use get_appointment_group for one group's full detail by id, and next_appointment to find the next open slot instead of browsing every group. |
| get_appointment_groupA | Get a single appointment group's core record — id, title, context_codes, workflow_state, and location — by id. None of its time slots, per-slot reservations, or participant counts come back unless you pass include with "appointments", "child_events", or "participant_count" respectively; omit include and you get only the core record. Find the id with list_appointment_groups. Use list_appointment_group_users or list_appointment_group_groups to see who has actually reserved a slot, and next_appointment to find the next slot still open to sign up for. |
| create_appointment_groupA | Create a new appointment group (Canvas Scheduler sign-up slots) in one or more contexts, e.g. ["course_123"], and return the created group object (id, title, workflow_state, context_codes). New groups start workflow_state "pending" (unpublished, invisible to participants) unless publish=true — once published, Canvas will not let it go back to unpublished, so confirm with get_appointment_group before setting it. participant_visibility defaults to "private"; set it to "protected" so signed-up participants can see each other's sign-ups. Add new_appointments as [start_at, end_at] ISO 8601 pairs to create the bookable time slots up front, or add more later with update_appointment_group. Each call creates another group — there is no dedup against an existing title. Requires permission to manage the Scheduler in every context listed. |
| update_appointment_groupA | Update an existing appointment group by id — only the fields you pass are changed — and return the updated group object. Set publish=true to make a draft group visible to participants; Canvas will not let you set it back to false once published. Add new_appointments as [start_at, end_at] ISO 8601 pairs to create additional time slots — existing slots are left alone and there is no removal here. This tool cannot change participant_type, participant_visibility, or the per-participant appointment limits set at create_appointment_group; those are fixed at creation. Find the id with list_appointment_groups. Requires permission to manage the Scheduler in the group's context. |
| delete_appointment_groupA | Delete an appointment group by id, canceling every time slot and reservation on it and emailing every signed-up participant, then return the deleted group object. This is permanent: the group and its slots cannot be recovered afterward. Pass cancel_reason to include why in that cancellation email. Find the id with list_appointment_groups, and check list_appointment_group_users or list_appointment_group_groups first if you need to know who will be notified. Requires permission to manage the Scheduler in the group's context. |
| list_appointment_group_usersA | List the individual Canvas users who have a reservation in this appointment group, returning each as a user object (id, name). Only meaningful when the group's participant_type is "User" — a Group-type group returns an empty list here; use list_appointment_group_groups instead for those. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Find the appointment_group_id with list_appointment_groups, or use get_appointment_group with include=["participant_count"] for just a count instead of the full list. |
| list_appointment_group_groupsA | List the student groups that have a reservation in this appointment group, returning each as a group object (id, name, group_category_id, members_count) — the same shape list_groups returns. Only meaningful when the group's participant_type is "Group" — a User-type group returns an empty list here; use list_appointment_group_users instead for those. Fetches every page (100 per request) and fails with a 'Results are incomplete' error instead of silently truncating. Find the appointment_group_id with list_appointment_groups. |
| next_appointmentA | Get the single next open time slot the current user is still eligible to sign up for, searched across every appointment group the user can reserve in (or only the appointment_group_ids you pass), and return it as a one-element array of calendar-event objects — or an empty array if nothing is open. This is about availability, not history: it excludes slots the user already reserved and slots that are full, but does not exclude a whole group just because the user holds a reservation in one of its other slots. Use list_appointment_groups with scope="reservable" to browse every open group instead of just the next slot, and list_appointment_group_users to see existing reservations. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| canvas-accessibility-sweep | Educator and learning-designer skill for a pre-launch accessibility and broken-link sweep of a Canvas course. Walks the structural accessibility audit and the link audit over a course's pages, assignments, syllabus, announcements, and (optionally) quizzes, then produces a prioritised remediation list you can work through in the Canvas editor. Trigger phrases include "accessibility sweep", "accessibility audit", "check course accessibility", "a11y check", "WCAG scan", "alt text audit", "broken links", "check my course for broken links", "pre-launch course check", or "course QC for accessibility". |
| canvas-admin-roster | Admin skill for walking the Canvas account hierarchy: list accounts and sub-accounts, see courses and users under each, look up which canned reports are available, and enroll or remove users from a specific course — one action at a time. Trigger phrases include "admin roster", "list accounts", "sub accounts", "account users", "users in this account", "enroll a user", "remove an enrollment", "account reports", or "what accounts can I see". Uses write tools: enroll_user, remove_enrollment. The workflow asks you to confirm before each write. |
| canvas-at-risk-students | Identify at-risk Canvas students and send targeted outreach. Surfaces students with missing assignments, low grades, or declining submission patterns — then lets you message them directly. Trigger phrases include "at-risk students", "struggling students", "who's falling behind", "students to check in with", or "missing submissions". Uses write tools: send_conversation. The workflow asks you to confirm before each write. |
| canvas-course-pulse | Educator skill for tracking week-over-week course health trends in Canvas. Surfaces assignment performance trends, login activity, engagement gaps, and struggling students across a longer time horizon than a daily check. Trigger phrases include "course pulse", "course health", "course trends", "week-over-week performance", "how is the course going", "engagement trends", "who isn't logging in", or "course activity over time". |
| canvas-course-qc | Learning designer quality-control checklist for Canvas courses. Walks modules, pages, assignments, and rubrics to surface structural issues — broken item sequences, missing rubrics, empty modules, unpublished content — before a course goes live. Trigger phrases include "course QC", "course quality check", "review course structure", "pre-launch audit", "check course content", or "canvas course review". |
| canvas-course-requirements | Student plan for one Canvas course, built from the requirement graph instead of guessed from raw module flags. Shows what is genuinely left, what is blocked, and what Canvas cannot yet say either way, with the endpoint and field behind every verdict. Trigger phrases include "what do I still have to do in this course", "what's left in this course", "am I done with this module", "what's blocking me", "why is this item locked", "module requirements", or "course requirements". |
| canvas-discussion-facilitator | Educator skill for browsing, reading, replying to, and creating Canvas discussion topics. Surfaces active threads, unread entries, and announcement activity — then lets you post replies or create new topics without leaving your agent session. Trigger phrases include "discussion board", "course discussions", "reply to discussion", "create a discussion", "what's in the discussion forum", "check announcements", or "post to discussion". Uses write tools: create_discussion, post_discussion_entry, update_discussion. The workflow asks you to confirm before each write. |
| canvas-gradebook-audit | Audit gradebook changes and grade edit history in Canvas. Surfaces who changed which grades, when, and by how much — across a date range or for a specific student. Unique to canvas-lms-mcp (no competitor exposes gradebook history). Trigger phrases include "grade audit", "who changed this grade", "gradebook history", "grade edits", "check for grade changes", or "grade integrity". |
| canvas-grading-pass | Educator grading workflow for Canvas. Walks through ungraded submissions one at a time, applying rubric assessments and score comments with explicit confirmation before each write. Trigger phrases include "grade submissions", "start grading", "grading pass", "mark submissions", "grade this assignment", or "rubric grading". Uses write tools: comment_on_submission, grade_submission, submit_rubric_assessment. The workflow asks you to confirm before each write. |
| canvas-morning-check | Educator morning briefing for Canvas. Surfaces ungraded submissions, participation gaps, upcoming deadlines, and flagged students across all active courses — in under a minute. Trigger phrases include "morning Canvas check", "what needs my attention today", "grading queue", "educator briefing", "what's pending", or "Canvas daily summary". |
| canvas-office-hours | Educator skill for running office hours through Canvas Scheduler appointment groups. Create and publish sign-up slots for a course, list existing groups and their time slots, and see which students (or student groups) have reserved — one confirmed action at a time. Trigger phrases include "office hours", "appointment group", "Canvas Scheduler", "sign-up slots", "create office hours", "who signed up for office hours", "manage appointment slots", "publish office hours", or "schedule office hours". Uses write tools: create_appointment_group, delete_appointment_group, update_appointment_group. The workflow asks you to confirm before each write. |
| canvas-outcome-tracker | Track student mastery of learning outcomes in Canvas. Shows outcome rollups by student, mastery distribution across the class, and which outcomes have the lowest proficiency rates. Built for accreditation reviews, program assessment, and advising. Trigger phrases include "outcome tracker", "learning outcomes", "mastery data", "accreditation report", "outcome mastery", or "who hasn't mastered". |
| canvas-peer-review-tracker | Educator skill for tracking peer-review assignments in Canvas. Lists who has been asked to review whom, who has submitted versus who is still pending, and lets you assign new reviewers or send reminder messages — one student at a time. Trigger phrases include "peer reviews", "who hasn't done their peer review", "peer review status", "assign a peer reviewer", "remind students about peer reviews", or "peer review tracker". Uses write tools: create_peer_review, delete_peer_review, send_conversation. The workflow asks you to confirm before each write. |
| canvas-quiz-review | Educator skill for reviewing Canvas quiz performance and regrading individual question scores. Surfaces struggling questions, low-scoring students, and per-student answer breakdowns — then lets you adjust scores for specific questions without leaving your agent session. Unique to canvas-lms-mcp (no other Canvas MCP server exposes quiz tools). Trigger phrases include "quiz review", "quiz results", "struggling quiz questions", "quiz scores", "regrade a quiz question", "quiz performance", or "student quiz answers". Uses write tools: score_quiz_question. The workflow asks you to confirm before each write. |
| canvas-student-todo | Student action list for Canvas. Surfaces every incomplete to-do item, missing submission, and upcoming deadline in one prioritised view — no calendar, no context switching. Trigger phrases include "what do I need to do", "my Canvas to-dos", "student to-do list", "what's missing", "catch me up", or "what should I work on". |
| canvas-syllabus-coach | Learning designer skill for reviewing and improving Canvas course syllabi and front pages. Reads the syllabus and key pages, proposes clarity and completeness improvements, then optionally applies the edits with your confirmation. Trigger phrases include "syllabus review", "improve the syllabus", "syllabus coach", "course front page", "update course description", "review course pages", or "polish the syllabus". Uses write tools: create_page, update_course, update_page. The workflow asks you to confirm before each write. |
| canvas-week-plan | Student weekly planner for Canvas. Pulls upcoming assignments, due dates, current grades, pending submissions, and peer review obligations into a single prioritised plan for the week ahead. Trigger phrases include "plan my week", "what's due this week", "weekly Canvas plan", "week ahead", or "upcoming assignments". |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| Course Structure | Interactive course structure tree |
| Institution Announcements | Interactive institution announcements panel |
TDQS
Scored across 185 tools
Descriptions are unusually diligent about carving boundaries (e.g. list_quiz_questions vs get_quiz_question_responses vs list_new_quiz_items, or list_course_users vs list_students vs list_account_users), which rescues a lot. But the sheer number of near-pairs still creates real misselection risk: get_course_structure vs view_course_structure return the same payload, list_discussions vs list_group_discussions vs list_announcements share an index, and the eight get_outcome_* tools plus three gradebook-history tools are hard to tell apart at a glance. New Quiz vs Classic Quiz pairs are distinguished only by remembering which engine a given ID belongs to.
The dominant pattern is a clean snake_case verb_noun convention (list_*, get_*, create_*, update_*, delete_*, search_*, set_*) applied consistently across ~150 tools. Outliers are few and purposeful — project_grade, explain_grade, explain_grading_policy, check_course_setup, audit_course_links, next_appointment, health_check — where the verb is descriptive rather than CRUD. No mixed casing.
185 tools for one LMS integration is an extreme surface that no agent can select from reliably; the context cost alone is prohibitive. Whole clusters (8 outcome tools, 3 gradebook-history tools, 4 quiz-accommodation tools, 4 appointment-group membership tools, account admin tooling) sit far outside a typical instructor/student workflow. This needs aggressive grouping or profile-based subsetting.
Coverage is remarkably broad — courses, assignments, overrides, submissions, rubrics, both quiz engines, files, modules, pages, discussions, enrollments, groups, outcomes, analytics, accounts, calendar, conversations, peer reviews, migrations, Scheduler, and several cross-cutting audit/advisor tools. Gaps are minor and mostly life-cycle: no delete_course, no folder create/delete, no update_file, no Classic quiz creation, and no group-scoped discussion reply or edit.