canvas-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| CANVAS_TOOLS | No | Strict allowlist of tool names to publish, e.g. canvas_auth_status,canvas_get_gradebook. | |
| CANVAS_TIMEOUT | No | Seconds per API request. | 30 |
| CANVAS_BASE_URL | Yes | Your Canvas base URL, e.g. https://yourschool.instructure.com. Do not include /api/v1. | |
| CANVAS_PER_PAGE | No | Canvas page size. | 100 |
| CANVAS_API_TOKEN | Yes | Canvas API token from Account → Settings → New Access Token. | |
| CANVAS_MAX_CHARS | No | Response size cap, with an explicit truncation notice. | 20000 |
| CANVAS_MAX_PAGES | No | Pagination cap. Results past it are marked _truncated. | 10 |
| CANVAS_REDACT_PII | No | Set to 1 to pseudonymise emails, login ids, SIS ids. | 0 |
| CANVAS_MAX_RETRIES | No | Attempts on rate limits and 5xx. | 3 |
| CANVAS_TOOL_GROUPS | No | Comma-separated tool groups to publish. Groups: diagnostics, courses, people, assignments, grading, content, communication. | |
| CANVAS_DOWNLOAD_DIR | No | Where downloaded files and submissions land. | ./canvas-downloads |
| CANVAS_MCP_ENV_FILE | No | Path to a .env file to load first. | |
| CANVAS_DISABLE_TOOLS | No | Denylist of tool names to suppress, applied after everything else. | |
| CANVAS_ENABLE_WRITES | No | Set to 0 for a strictly read-only server. | 1 |
| CANVAS_MAX_UPLOAD_MB | No | Refuse larger local files. | 100 |
| CANVAS_UPLOAD_TIMEOUT | No | Seconds for file uploads. | 300 |
| CANVAS_ALLOW_DESTRUCTIVE | No | Set to 1 to publish the five delete/raw-write tools. | 0 |
| CANVAS_DEFAULT_COURSE_ID | No | Default course id used when a tool's course_id is omitted. |
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": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| canvas_auth_statusA | Check Canvas connectivity, identity, and which tool tiers are enabled. Reveals no token material. Call this first whenever another Canvas tool
fails, or when a tool you expected is missing — the |
| canvas_api_getA | Escape hatch: GET any Canvas REST endpoint without a dedicated tool. Canvas publishes well over a thousand operations; the tools here cover the common teaching ones. Use this for the rest. Read-only by construction — it cannot issue a write even if asked to. Args: path: path under /api/v1, e.g. "courses/12345/gradebook_history/days". A full URL is also accepted. params_json: optional JSON object of query parameters, e.g. '{"per_page": 20, "include[]": "submission"}'. max_chars: bound on the returned payload (0 = the server default). |
| canvas_list_coursesA | List the courses the authenticated user can see. Start here when you do not know the course id. The id in the output is what every other tool's course_id parameter wants. Args: enrollment_state: active (default), completed, or invited_or_pending. enrollment_type: filter by your role — teacher, ta, student, observer, designer. Empty for all roles. |
| canvas_get_courseA | Get one course: teachers, student count, and the syllabus as plain text. Args: course_id: numeric id from the course URL; falls back to CANVAS_DEFAULT_COURSE_ID. max_chars: bound on the returned payload (0 = the server default). |
| canvas_list_sectionsA | List a course's sections with their enrollment counts. Sections matter for anything scoped to part of a roster — section-level due dates, a lab subsection, or enrolling someone into one specific section rather than the course default. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_update_courseA | Edit course settings. MUTATES the live course. Only the fields you pass change. Publishing a course makes it visible to every enrolled student immediately, and Canvas will not let you unpublish once a student has submitted work — confirm before setting published=True. Args: name: new course name, or empty to leave unchanged. course_code: new short code, or empty to leave unchanged. start_at: ISO 8601 UTC start, e.g. 2026-08-26T05:00:00Z. end_at: ISO 8601 UTC end. published: True to publish, False to unpublish, omit to leave alone. default_view: landing page — feed, wiki, modules, syllabus, assignments. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_update_syllabusA | Replace the course syllabus body. MUTATES the live course page. This OVERWRITES the existing syllabus wholesale — Canvas keeps no version history for it, so read canvas_get_course first if the current text matters, and show the instructor what is being replaced. Args: body: the new syllabus HTML. Plain text works, but newlines are not converted to , so pass HTML if you want formatting. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_studentsA | List the students enrolled in a course. FERPA: returns student names, and email addresses when include_email=True. With CANVAS_REDACT_PII=1 identifiers come back as stable hashes instead. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. include_email: also request email addresses (default False). search_term: optional name/login substring filter (3+ characters). |
| canvas_list_enrollmentsA | List enrollments, including the enrollment_id needed to change one. canvas_list_students returns users; removing or modifying somebody needs the enrollment id, which is a different number. Fetch it here first — passing a user id to canvas_remove_enrollment silently targets the wrong record or 404s. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. role: StudentEnrollment, TeacherEnrollment, TaEnrollment, ObserverEnrollment, DesignerEnrollment. Empty for all. state: active, invited, concluded, completed, inactive. Empty for all. |
| canvas_enroll_userA | Enrol a user in the course. MUTATES the roster. Defaults to state=invited and notify=False: the person gets an invitation they must accept, and no email goes out until you ask for one. Pass enrollment_state="active" to place them straight onto the roster. Args: user_id: numeric Canvas user id. "sis_user_id:ABC123" enrols by SIS id instead, which is usually what a registrar export gives you. enrollment_type: StudentEnrollment, TeacherEnrollment, TaEnrollment, ObserverEnrollment, or DesignerEnrollment. enrollment_state: invited (default) or active. notify: send Canvas's notification email (default False). section_id: enrol into a specific section instead of the default one. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_assignmentsA | List assignments in a course, with due dates and needs-grading counts. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. bucket: optional filter — past, overdue, undated, ungraded, unsubmitted, upcoming, future. search_term: optional title substring filter. |
| canvas_get_assignmentA | Get one assignment, with its description rendered to plain text. Args: assignment_id: numeric assignment id. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. max_chars: bound on the returned payload (0 = the server default). |
| canvas_list_assignment_groupsA | List assignment groups and their gradebook weights. A course that grades by weighted categories ("Participation 20%, Papers 50%...") carries those weights here, not on the assignments. Read this before reasoning about what a score is worth. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_create_assignment_groupA | Create an assignment group (a gradebook category). MUTATES the course. Args: name: group name, e.g. "Response Papers". group_weight: percentage of the final grade, if the course uses weighted groups. Omit for unweighted. position: 1-based slot in the group list; omit to append. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_create_assignmentA | Create an assignment. MUTATES the course. Defaults to UNPUBLISHED so students do not see it until you publish — pass published=True only when the instructor says it is ready. Args: name: assignment title. description: body HTML shown to students. points_possible: max score; omit for an ungraded assignment. due_at: ISO 8601 UTC, e.g. 2026-09-10T04:59:59Z. Canvas stores UTC, so an 11:59pm local deadline is not 23:59Z — convert first. unlock_at: ISO 8601 UTC; students cannot see it before this. lock_at: ISO 8601 UTC; submissions close after this. submission_types: comma-separated, from online_text_entry, online_upload, online_url, online_quiz, discussion_topic, media_recording, student_annotation, on_paper, external_tool, none. grading_type: points (default), percent, letter_grade, gpa_scale, pass_fail, not_graded. published: visible to students immediately (default False). assignment_group_id: group to file it under; see canvas_list_assignment_groups. omit_from_final_grade: True to score it without affecting the total. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_update_assignmentA | Edit an existing assignment. MUTATES the course. Only the fields you pass are changed; omitted ones are left alone. Two edits have downstream gradebook effects worth flagging to the instructor: publishing an assignment students have not seen, and changing points_possible on one that is already graded (every existing score is silently re-scaled in the totals). Args: assignment_id: numeric assignment id. name: new title, or empty to leave unchanged. description: new body HTML, or empty to leave unchanged. points_possible: new max score, or omit to leave unchanged. due_at: new ISO 8601 UTC due date, or empty to leave unchanged. unlock_at: new ISO 8601 UTC availability date. lock_at: new ISO 8601 UTC close date. published: True/False to change visibility, or omit to leave alone. assignment_group_id: move it to another gradebook category. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_submissionsA | List submissions for an assignment: status, score, timestamps, lateness. Metadata only — call canvas_get_submission for a student's actual work. Args: assignment_id: numeric assignment id. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. include_ungraded: keep submissions with no score yet (default True). only_submitted: drop students who have not turned anything in. |
| canvas_get_submissionA | Get one student's submission: body text, attachments, and comments. FERPA: this returns a named student's submitted work. Treat accordingly — and note that attachment contents are not inlined, only listed; use canvas_download_submissions to fetch the files themselves. Args: assignment_id: numeric assignment id. user_id: numeric Canvas user id, or "self". course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. max_chars: bound on the returned payload (0 = the server default). |
| canvas_get_gradebookA | Get the whole gradebook as one student-by-assignment table. One call instead of N calls to canvas_list_submissions. Use it to find missing work, spot an assignment nobody passed, or summarise standing before office hours. FERPA: this is the full class record. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. assignment_ids: comma-separated ids to restrict to; empty for all. include_names: label rows with student names as well as ids. max_chars: bound on the returned payload (0 = the server default). |
| canvas_download_submissionsA | Download every file attachment for an assignment to a local folder. Writes files to disk on the machine running this server. Each lands as
FERPA: this copies student work out of Canvas onto local storage. Make sure the instructor knows where it is going and cleans it up afterwards. Args: assignment_id: numeric assignment id. dest_dir: destination folder; defaults to CANVAS_DOWNLOAD_DIR, or ./canvas-downloads. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. max_files: safety cap on how many files to pull (default 100). |
| canvas_grade_submissionA | Post a grade and/or a comment to a submission. MUTATES STUDENT RECORDS. Writes to the live gradebook immediately and cannot be undone from here. ALWAYS show the instructor the exact student, assignment, grade, and comment text and get an explicit go-ahead before calling. Never call this to "try" something or as part of exploratory reasoning. Args: assignment_id: numeric assignment id. user_id: numeric Canvas user id of the student. grade: points ("18"), percentage ("88%"), or a letter grade. Omit to post a comment only. comment: comment posted alongside the grade; the student sees it. excused: True to excuse the student from the assignment entirely. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_bulk_gradeA | Post many grades to one assignment at once. MUTATES STUDENT RECORDS. Canvas processes this asynchronously and returns a Progress object, so the grades appear a few seconds later. There is no partial-failure report — read back with canvas_list_submissions to confirm. A bulk write is the highest-consequence call in this server. Show the instructor the complete table of student ids, grades, and comments and get an explicit go-ahead; never assemble one from inference. Args: assignment_id: numeric assignment id. grades_json: JSON object keyed by user id, e.g. '{"101": {"grade": "18", "comment": "Clear thesis."}, "102": {"grade": "15"}}'. A bare string value is accepted as the grade: '{"101": "18"}'. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_pagesA | List wiki pages in a course (titles and url slugs, not bodies). The Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. search_term: optional title substring filter. |
| canvas_get_pageA | Get one wiki page's body as plain text. Args: page_url: the page's url slug (from canvas_list_pages). course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. max_chars: bound on the returned payload (0 = the server default). |
| canvas_create_pageA | Create a wiki page. MUTATES the course. Defaults to UNPUBLISHED. Canvas derives the page's url slug from the
title; the returned Args: title: page title. body: page HTML. published: visible to students immediately (default False). front_page: make this the course home page. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_update_pageA | Edit a wiki page. MUTATES the course. Only the fields you pass change. Passing body REPLACES the whole page — read canvas_get_page first if you mean to append. Note that canvas_get_page returns plain text, so round-tripping it through this tool will flatten the page's existing HTML formatting. Args: page_url: the page's url slug (from canvas_list_pages), not its id. title: new title, or empty to leave unchanged. Renaming does NOT change the url slug, so existing links keep working. body: new page HTML, or empty to leave unchanged. published: True/False to change visibility, or omit to leave alone. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_modulesA | List course modules, optionally with their items — the course outline. This is the fastest way to see how a course is actually structured week by week. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. with_items: inline each module's items (default True). max_chars: bound on the returned payload (0 = the server default). |
| canvas_create_moduleA | Create a course module. MUTATES the course. A module is an empty container until you add items with canvas_create_module_item. Defaults to UNPUBLISHED. Args: name: module title, e.g. "Week 3 — Coding agents". position: 1-based slot in the module list; omit to append at the end. published: visible to students immediately (default False). course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_update_moduleA | Edit or publish a module. MUTATES the course. Publishing a module publishes its items too, which is the usual way a week's content goes live for students. Only the fields you pass change. Args: module_id: numeric module id. name: new title, or empty to leave unchanged. position: new 1-based slot, or omit to leave unchanged. published: True/False to change visibility, or omit to leave alone. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_create_module_itemA | Add an item to a module. MUTATES the course. Which id field you need depends on item_type: Assignment / Quiz / Discussion / File -> content_id (the object's id) Page -> page_url (the slug) ExternalUrl / ExternalTool -> external_url SubHeader -> neither; title is the item Args: module_id: numeric module id. title: item label shown in the module list. item_type: one of Assignment, Quiz, File, Page, Discussion, SubHeader, ExternalUrl, ExternalTool. content_id: id of the linked object, for the types that need one. page_url: page slug, for item_type=Page. external_url: target, for item_type=ExternalUrl or ExternalTool. position: 1-based slot within the module; omit to append. indent: nesting level, 0 for top level. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_quizzesA | List quizzes in a course. Note: this covers Classic Quizzes. Institutions on New Quizzes see them as assignments with submission_type=external_tool instead — check canvas_list_assignments if a quiz you expect is missing here. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_filesB | List files uploaded to a course. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. search_term: optional filename substring filter (3+ characters). |
| canvas_download_fileA | Download one course file to local disk. Writes to the machine running this server, not the user's laptop, if those differ. Args: file_id: numeric file id (from canvas_list_files). dest_dir: destination folder; defaults to CANVAS_DOWNLOAD_DIR, or ./canvas-downloads. name: filename to save as; defaults to the Canvas display name. |
| canvas_upload_fileA | Upload a local file into the course's Files area. MUTATES the course. Three-step Canvas dance, handled here: register the upload, POST the bytes to the storage host, then confirm. The Canvas token is never sent to the storage host. Args: local_path: absolute path to the file on the machine running this server. parent_folder_path: Canvas folder, e.g. "course files/week03". Created if it does not exist. name: name to store it under; defaults to the local filename. on_duplicate: "rename" (default, keeps both) or "overwrite". course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_announcementsB | List a course's announcements, most recent first, with their text. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. max_chars: bound on the returned payload (0 = the server default). |
| canvas_post_announcementA | Post an announcement. MUTATES the course — students are notified. Show the instructor the exact title and body and get explicit approval before calling. Canvas emails the whole roster on post, so deleting the announcement afterwards does not unsend it. Pass delayed_post_at to schedule instead: the announcement is created but stays unpublished until that moment, which leaves a window to review or cancel it. Args: title: announcement subject line. message: body (HTML allowed). delayed_post_at: ISO 8601 UTC; publish then instead of immediately. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_discussionsB | List discussion topics in a course. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_get_discussionA | Get a discussion topic with its full reply thread as plain text. FERPA: student posts are student work, attributed by name. Use this to summarise a week's discussion, not to bulk-export it. Args: topic_id: numeric discussion topic id. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. max_chars: bound on the returned payload (0 = the server default). |
| canvas_create_discussionA | Create a discussion topic. MUTATES the course. Defaults to UNPUBLISHED so you can review it before students see it. Publishing a discussion notifies students who have announcements and discussions turned on. Args: title: topic title. message: prompt body (HTML allowed). published: visible to students immediately (default False). require_initial_post: students must post before seeing replies. threaded: allow nested replies (default True). pinned: pin to the top of the discussions list. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_list_calendar_eventsA | List calendar events (and optionally assignment due dates) for a course. Args: course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. start_date: YYYY-MM-DD lower bound; empty for Canvas's default window. end_date: YYYY-MM-DD upper bound. include_assignments: also return assignment due dates as events. |
| canvas_create_calendar_eventA | Create a calendar event on the course calendar. MUTATES the course. Appears on every enrolled student's calendar. Good for class meetings, office hours, and guest lectures — not for assignment due dates, which belong on the assignment itself so the gradebook knows about them. Args: title: event title. start_at: ISO 8601 UTC start, e.g. 2026-09-10T18:00:00Z. end_at: ISO 8601 UTC end; omit for a point-in-time event. description: event body (HTML allowed). location_name: room or place. course_id: numeric course id; defaults to CANVAS_DEFAULT_COURSE_ID. |
| canvas_message_studentsA | Send a Canvas inbox message to one or more students. NOTIFIES PEOPLE. This reaches students directly and cannot be recalled. Show the instructor the recipient list and the exact text, and get explicit approval, every time. Defaults to individual conversations: each recipient gets their own thread and cannot see who else was written to. Only pass group_conversation=True when the students are meant to see each other — a group project thread, say — because otherwise it discloses the recipient list to everyone on it. Args: recipient_ids: comma-separated Canvas user ids, or a JSON array. subject: message subject. body: message text. group_conversation: put all recipients in one shared thread. course_id: numeric course id; scopes the message to the course so students can reply. Defaults to CANVAS_DEFAULT_COURSE_ID. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 42 tools
Each tool targets a distinct resource and action, and descriptions actively head off confusion (e.g. canvas_list_students returns users while canvas_list_enrollments returns enrollment ids; canvas_list_submissions is metadata-only while canvas_get_submission returns the work). A few pairs sit close together (download_submissions vs download_file, get_gradebook vs list_submissions, api_get as a catch-all), but none is genuinely ambiguous.
Nearly all tools follow a canvas_<verb>_<noun> pattern (get_assignment, list_courses, create_page, update_module, download_file, grade_submission). Minor deviations exist — canvas_auth_status is noun-noun and canvas_api_get inverts the pattern — but the convention is largely predictable.
42 tools is heavy and pushes past the comfortable range, but the Canvas teaching domain is genuinely broad (gradebook, submissions, pages, modules, files, discussions, calendar, messaging). Each tool maps to a distinct operation and an api_get escape hatch absorbs the long tail, so the count is defensible though on the borderline of unwieldy.
Create/read/update coverage is strong across assignments, pages, modules, discussions, and grading, but deletions are almost entirely absent (no delete page/module/assignment/file/discussion). Notably, canvas_list_enrollments references a canvas_remove_enrollment tool that is not published, leaving a dangling handle that would trap an agent trying to drop a student.