Canvas Agent
Allows AI assistants to manage courses, assignments, grades, submissions, rubrics, modules, discussions, calendar events, analytics, enrollments, and more through the Instructure Canvas LMS API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Canvas Agent list my assignments due this week"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Canvas Agent
MCP server that connects AI assistants — Google's Antigravity CLI, Claude Code, and Claude Desktop — to Instructure Canvas LMS. Teachers and administrators can manage courses, assignments, grades, and more through natural language.
Looking to install Canvas Agent? Follow the setup guide at hughsibbele.github.io/Canvas-Agent — no technical background required.
Architecture
Canvas Agent ships as three MCP servers from one npm package, split by intent. The setup wizard registers all three by default; users who want to save context can drop admin or extras from their MCP config.
AI client (Claude Code / Claude Desktop / Antigravity CLI)
├─ spawns canvas-agent (core, 80 tools — daily teaching/grading)
├─ spawns canvas-agent-admin (18 tools — course/section/enrollment lifecycle)
└─ spawns canvas-agent-extras (36 tools — outcomes, groups, pages, files, messaging, …)
└─ MCP stdio transport
└─ Canvas REST API (bearer token auth)The three bins share a single import graph and a single per-course vault, so anonymization tokens stay consistent across servers. Core also includes a describe_canvas_mcps tool so the AI can tell the user which other bin to mount when a needed tool isn't loaded.
Component | Path | Role |
Core MCP entry point |
| The 79 daily teaching/grading tools + the |
Admin MCP entry point |
| The 18 course/section/enrollment lifecycle tools |
Extras MCP entry point |
| The 36 outcomes/groups/pages/files/messaging/late-policy/classic-quizzes tools |
CLI dispatcher |
|
|
Canvas API client |
| Thin fetch wrapper with automatic pagination ( |
Tool modules |
| One file per Canvas domain. Mixed-bucket files export per-bucket registrars (e.g. |
Privacy pipeline |
| Three-stage redaction at the MCP boundary: token-swap structured PII fields, redact student names inside free text, wrap untrusted content with prompt-injection delimiters. Per-course vault tracks role (student/teacher/unknown); teachers are exempt. Map lives in |
Setup wizard |
| Interactive CLI that validates credentials, detects Claude Code / Desktop / Antigravity CLI, and registers all three v2 bins. |
Tool-routing assertion harness |
| Boots all three split servers via the MCP SDK and asserts each exposes exactly its bucket (80 / 18 / 36) with no cross-server name collisions. Run via |
Landing site |
| Static GitHub Pages site with the end-user setup guide |
Tool modules
Module | File | v2 bin(s) | Covers |
Courses |
| core + admin | core: list courses, terms, assignment groups, modules, grading periods. admin: create/update/delete/conclude/reset/copy course, navigation tabs. |
Assignments |
| core | CRUD assignments, batch update dates |
Submissions |
| core | List/download submissions, download discussion entries |
Grading |
| core + extras | core: grade/bulk-grade/post/hide, missing & gradeable students. extras: late policy, grading standards. |
Rubrics |
| core | CRUD rubrics, copy across assignments/courses, associate with display toggles, link to outcomes, view/edit/delete assessments |
Outcomes |
| extras | List outcomes/groups, outcome results, mastery rollups |
Modules |
| core | CRUD modules and module items, publish modules |
Pages |
| extras | CRUD pages, front page, page revisions |
Discussions |
| core | CRUD discussions and batch updates (download entries lives in submissions.ts) |
Quizzes (Classic) |
| extras | List/get/update Classic Quizzes |
New Quizzes |
| core | List/CRUD New Quizzes, quiz items, accommodations, generate quiz reports |
Calendar |
| core | CRUD calendar events |
Files |
| extras | List/get/update/delete files, folders, quota |
Enrollments |
| core + admin | core: list students/sections/users, get profile. admin: crosslist, create/update/delete sections, enroll/drop users, move student. |
Communication |
| core + extras | core: post submission comment. extras: send_message, create_announcement. |
Groups |
| extras | Group sets, groups, membership, auto-distribute |
Analytics |
| core + extras | core: course/student activity, assignment analytics, student summaries. extras: messaging data. |
Scheduling |
| core + extras | core: assignment dates, batch updates, overrides, schedule overview. extras: classic-quiz dates. |
Meta |
| core |
|
Related MCP server: Canvas MCP
Migrating from v1.x
v2 splits the v1 single-MCP surface into core / admin / extras. If your existing config has just canvas-agent, you'll keep working but lose access to anything that moved out of core. Add the relevant bin to your MCP config:
{
"mcpServers": {
"canvas-agent": { "command": "npx", "args": ["-y", "canvas-agent"] },
"canvas-agent-admin": { "command": "npx", "args": ["-y", "canvas-agent-admin"] },
"canvas-agent-extras": { "command": "npx", "args": ["-y", "canvas-agent-extras"] }
}
}The setup wizard (npx canvas-agent setup) registers all three by default — running it again is the simplest upgrade path.
Tool → bin lookup (alphabetical)
If you used a tool in v1, this table tells you which v2 bin it lives in. Tools not listed here are in canvas-agent (core).
Tool | v2 bin |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The vault, anonymizer, and reveal CLI are unchanged — no data migration. You can also ask the AI "describe canvas-agent's MCPs" and it will surface the same info via the describe_canvas_mcps tool in core.
Development
git clone https://github.com/hughsibbele/Canvas-Agent.git
cd Canvas-Agent
npm install
cp .env.example .env # add your CANVAS_API_URL and CANVAS_API_TOKEN
npm run build
node dist/cli.js # start the core MCP server (default canvas-agent bin)
node dist/servers/admin.js # start admin server directly
node dist/servers/extras.js # start extras server directly
node dist/cli.js setup # run the setup wizard
npm test # boot all three servers and assert routingnpm run dev starts tsc --watch for iterating on tool modules.
Adding a tool
Decide which bucket it belongs to (core / admin / extras) — see V2_BUILD_PLAN.md for the rationale on existing tools.
Add the
server.tool(...)registration to the appropriateregister*Core/register*Admin/register*Extrasfunction insrc/tools/<domain>.ts. Create a new domain file + registrar if needed; export from the file and import/call in the matchingsrc/servers/<bucket>.ts.Update the routing manifest in
scripts/assert-tool-routing.mjsif the tool lands in admin or extras.npm testto verify.Rebuild (
npm run build) and restart your MCP client to pick up the new tool.
Each tool module follows the same pattern — define Zod input schemas and register them with server.tool(). Look at any existing module for the template.
Privacy & safety pipeline
Every Canvas response flows through a three-stage redaction pipeline in canvas-client.ts before it reaches the AI assistant:
Structured PII anonymizer (
src/anonymizer.ts). Walks the response and swaps student names, emails, login IDs, SIS ids, etc. for opaque tokens (Student_<6 hex>) on every user-shaped object. Records each user in a per-course vault keyed by Canvas user_id, with a derived role tag.Free-text name detector (
src/name-detector.ts). Scans free-text fields (discussion bodies, submission prose, comments, descriptions, filenames) for any known student's full name or sortable form ("Jane Doe"/"Doe, Jane") and replaces matches with the student's existing token. Uses Unicode-aware boundaries so names with apostrophes (O'Brien) and hyphens (Smith-Jones) match correctly. Per-course regex is cached and invalidated when the vault changes.Prompt-injection sandbox (
src/sandbox.ts). Wraps the same set of free-text fields with per-process nonce delimiters (<untrusted-canvas-content-NONCE>…</untrusted-canvas-content-NONCE>) so a downstream LLM treats student-authored content as data, not instructions. The nonce is process-random — a student can't guess it to forge a closing tag and "break out" of the sandbox.
On the write path, rehydrateText swaps tokens back to real names and strips any sandbox markers the LLM may have echoed back, so comments and announcements go out correctly addressed and don't leak protection markers into Canvas.
Roles — teachers stay readable
The vault tags each user as student, teacher, or unknown. Roles are derived from enrollment context (enrollments[].type, grader_* / assessor / edited_by / graded_by field positions) and merged monotonically (teacher > student > unknown, never downgrades). Known teachers skip tokenization entirely — their real names pass through to the AI. This keeps workflows like "did I grade this?" working and avoids treating staff as the subject of privacy protection.
CLI tools
canvas-agent reveal Student_a4f2c1 # decode a token (any course)
canvas-agent reveal Student_a4f2c1 --course 42 # single course
canvas-agent reveal --all --course 42 # dump every entry for a course
canvas-agent vault-gc # dry-run report of orphan vault rows
canvas-agent vault-gc --apply # actually prune them
canvas-agent vault-gc --course 42 --verbose # scope + show student-by-student detailvault-gc cleans up orphan rows that accumulated under the pre-1.5.0 id-vs-user_id bug, where each discussion entry / submission / comment minted a phantom vault row keyed by entry id instead of user id. Default mode is dry-run.
The whole pipeline can be disabled with CANVAS_AGENT_ANONYMIZE=0 (turns off both anonymization and free-text name detection) or CANVAS_AGENT_SANDBOX=0 (turns off only the prompt-injection wrapper).
Limits worth knowing
search_termqueries hit Canvas's real-name index. If the AI sends a token, Canvas finds nothing — reveal offline and search byuser_idinstead.download_submissionswrites submission attachments (Word docs, PDFs, etc.) as raw bytes to disk by design. Those files contain real student names and submission content; they stay on your local machine but aren't redacted.The free-text name detector matches only the full name and sortable form. First-name-only and last-name-only references go through unchanged (deliberate — too many false positives on common English words).
Account-level endpoints (
/accounts/*, top-level/conversationslists) carry no per-course context, so the per-course vault doesn't apply to them.
Canvas API gotchas
A few things worth knowing when adding or updating tools:
Grading periods scope grades and submissions to a single semester/term. Pass
grading_period_idto/courses/{id}/enrollments(returns per-periodcurrent_score/current_grade) and to/courses/{id}/students/submissions(returns only that period's submissions). Without it you get cumulative data, which is wrong for year-long courses where the gradebook resets each semester./courses/{id}/grading_periodsreturns a wrapped response —{"grading_periods": [...], "meta": {...}}— so thecanvasAllpagination helper won't flatten it. Usecanvasand unwrap manually (seelist_grading_periodsintools/courses.ts).Analytics endpoints don't support
grading_period_id—get_student_summaries,get_course_assignment_analytics, andget_student_assignment_dataalways return lifetime totals. For semester-scoped data, fetch submissions directly withgrading_period_id.
Links
npm: canvas-agent
Setup guide: hughsibbele.github.io/Canvas-Agent
Canvas API docs: canvas.instructure.com/doc/api
License
MIT
Available Tools
80 toolsadd_module_itemA
Add an item to a module. Required fields depend on type: Assignment/Discussion/File need content_id, Page needs page_url, SubHeader/ExternalUrl need title. For New Quizzes, use type='Assignment' with the New Quiz's assignment_id (not type='Quiz'). type='Quiz' is for Classic Quizzes only.
Inputs: type (required), course_id (required), module_id (required), title, +5 more.
associate_rubricA
Associate an existing rubric with one or more assignments. This is how you reuse a rubric across multiple assignments. Use list_rubrics to find the rubric_id.
Inputs: course_id (required), rubric_id (required), assignment_ids (required), hide_points, +3 more.
batch_update_assignmentsA
Update fields across multiple assignments at once. Does NOT support date fields — use batch_update_dates for date changes. Applies the same update to each assignment ID provided.
Inputs: updates (required), course_id (required), assignment_ids (required).
batch_update_datesA
Update dates for multiple assignments at once. Override-aware: if an assignment has section overrides, updates those instead of the (ignored) base date. For assignments with overrides, provide section_dates to set per-section times; if only due_at is given, all overrides get that same time. Provide an array of {assignment_id, due_at, section_dates?, unlock_at, lock_at} objects.
Inputs: course_id (required), date_updates (required).
batch_update_discussionsA
Update title/message/published across multiple discussions. Cannot update dates or points — use batch_update_dates with assignment_ids for date changes on graded discussions.
Inputs: updates (required), course_id (required), discussion_ids (required).
bulk_gradeA
Grade multiple students on one assignment at once. Returns a Progress object — the grading happens asynchronously.
Inputs: grades (required), course_id (required), assignment_id (required).
copy_rubricA
Duplicate an existing rubric. Copies title, criteria (with ratings, long descriptions, and outcome links), and free_form_criterion_comments. By default copies into the same course; pass target_course_id to copy across courses. Optionally renames and associates with one or more assignments. Display toggles (hide_score_total / hide_points / hide_outcome_results) are inherited from the source's primary association unless overridden. NOTE: outcome-linked criteria require the same outcome to be available in the target course; if it isn't, Canvas may strip the outcome link.
Inputs: source_course_id (required), source_rubric_id (required), new_title, hide_points, +4 more.
create_assignmentA
Create a new regular assignment in a course. For graded discussions, use create_discussion with points_possible instead. For New Quizzes, use create_new_quiz instead.
Inputs: name (required), course_id (required), due_at, lock_at, +7 more.
create_assignment_overrideA
Create a new date override for a specific section or set of students on an assignment. Use this to set section-specific due dates (e.g., different block start times for different sections).
Inputs: course_id (required), assignment_id (required), due_at, lock_at, +3 more.
create_calendar_eventA
Create a standalone calendar event (e.g. office hours, class sessions, review sessions). These are NOT assignments — to create graded items with due dates, use create_assignment.
Inputs: title (required), end_at (required), start_at (required), course_id (required), +3 more.
create_discussionB
Create a new graded or ungraded discussion topic.
Inputs: title (required), course_id (required), due_at, lock_at, +6 more.
create_moduleA
Create a new module in a course. Use list_modules to see existing modules first.
Inputs: name (required), course_id (required), position, unlock_at, +2 more.
create_new_quizA
Create a New Quiz (Quizzes.Next) in a course. Returns the created quiz object including its assignment_id.
Inputs: title (required), course_id (required), due_at, published, +2 more.
create_quiz_itemA
Create a question (item) in a New Quiz. This is the primary tool for adding questions.
INTERACTION TYPES AND THEIR DATA FORMATS:
"choice" (Multiple Choice) - Single correct answer from choices interaction_data: { "choices": [ { "item_body": "Answer A", "position": 1 }, { "item_body": "Answer B", "position": 2 }, { "item_body": "Answer C", "position": 3 } ] } scoring_data: { "value": "<id_of_correct_choice>" } NOTE: Create with placeholder scoring_data first. The API returns choices with generated IDs. Then use update_quiz_item to set the correct answer ID. Alternatively, scoring_data can reference by position index.
"true-false" (True/False) interaction_data: { "choices": [ { "item_body": "True", "position": 1 }, { "item_body": "False", "position": 2 } ] } scoring_data: { "value": "<id_of_correct_choice>" } Same approach as "choice" - create first, then update with correct choice ID.
"multi-answer" (Multiple Answer / Select All That Apply) interaction_data: { "choices": [ { "item_body": "Option A", "position": 1 }, { "item_body": "Option B", "position": 2 }, { "item_body": "Option C", "position": 3 } ] } scoring_data: { "value": ["<id_of_correct_1>", "<id_of_correct_2>"] }
"essay" (Essay / Free Response) interaction_data: {} scoring_data: { "value": "" }
"file-upload" (File Upload) interaction_data: {} scoring_data: { "value": "" }
"matching" (Matching) interaction_data: { "choices": [ { "item_body": "Term 1", "position": 1, "match_id": "m1" }, { "item_body": "Term 2", "position": 2, "match_id": "m2" } ], "matches": [ { "item_body": "Definition 1", "id": "m1", "position": 1 }, { "item_body": "Definition 2", "id": "m2", "position": 2 } ] } scoring_data: { "value": [{ "id": "<choice_id>", "match_id": "m1" }] }
"ordering" (Ordering) interaction_data: { "choices": [ { "item_body": "First item", "position": 1 }, { "item_body": "Second item", "position": 2 } ] } scoring_data: { "value": ["<id_in_correct_order>", "<id_in_correct_order>"] }
"categorization" (Categorization) interaction_data: { "categories": [ { "item_body": "Category A", "id": "cat1" }, { "item_body": "Category B", "id": "cat2" } ], "choices": [ { "item_body": "Item 1", "position": 1 }, { "item_body": "Item 2", "position": 2 } ] } scoring_data: { "value": [{ "id": "<choice_id>", "category_id": "cat1" }] }
"numeric" (Numeric Answer) interaction_data: {} scoring_data: { "value": "42" } or { "value": { "exact": 42, "margin": 0.1 } }
"fill-blank" (Fill in the Blank) interaction_data: {} scoring_data: { "value": ["acceptable answer 1", "acceptable answer 2"] }
"rich-fill-blank" (Fill in Multiple Blanks) interaction_data: { "blanks": [{ "id": "b1", "item_body": "blank1" }] } scoring_data: { "value": { "b1": ["answer1", "answer2"] } }
"formula" (Formula / Calculated) interaction_data: { "formula": "x + y", "variables": [{ "name": "x", "min": 1, "max": 10 }] } scoring_data: { "value": { "formula": "x + y", "margin": 0.01 } }
"hot-spot" (Hot Spot / Image Click) interaction_data: { "image_url": "...", "regions": [...] } scoring_data: { "value": "<region_id>" }
TIP: For choice-based questions, it is often easiest to create the item first with an empty or placeholder scoring_data, then GET the item to see the generated choice IDs, and finally UPDATE the item with the correct scoring_data referencing those IDs.
Inputs: title (required), course_id (required), item_body (required), scoring_data (required), +6 more.
create_rubricA
Create a new rubric in a course. Provide criteria as an array of objects, each with a description and an array of ratings (description + points). Optionally associate with an assignment immediately. Criteria can be linked to learning outcomes via learning_outcome_id (use list_outcomes to find IDs) — when linked, the criterion's mastery feeds into outcome rollups.
Inputs: title (required), criteria (required), course_id (required), assignment_id, +1 more.
delete_assignmentA
Permanently delete an assignment. This cannot be undone.
Inputs: course_id (required), confirm_name (required), assignment_id (required).
delete_calendar_eventA
Permanently delete a calendar event.
Inputs: event_id (required), confirm_title (required).
delete_moduleA
Permanently delete a module and all items within it. This cannot be undone.
Inputs: course_id (required), module_id (required), confirm_name (required).
delete_module_itemA
Remove an item from a module. This only removes the module entry — the underlying assignment/page/file is not deleted.
Inputs: item_id (required), course_id (required), module_id (required), confirm_title (required).
delete_quiz_itemA
Delete a question (item) from a New Quiz. This cannot be undone.
Inputs: item_id (required), course_id (required), assignment_id (required).
delete_rubricA
Permanently delete a rubric from a course. This removes it from all associated assignments and cannot be undone.
Inputs: course_id (required), rubric_id (required), confirm_title (required).
delete_rubric_assessmentA
Delete a single rubric assessment row, clearing that student's rubric grade for the assignment without removing the rubric or affecting other students. Find rubric_association_id and assessment_id by calling get_rubric with include=['assessments'].
Inputs: course_id (required), assessment_id (required), rubric_association_id (required).
describe_canvas_mcpsA
Describes the three Canvas-Agent MCPs (core/admin/extras), what tools live in each, and how to mount the other two. Call this when a user asks about Canvas-Agent's capabilities, or when you need a Canvas tool that doesn't appear to be registered — it's likely in admin or extras.
Inputs: no named parameters.
download_discussion_entriesA
Download all entries/replies for a discussion topic as a JSON file — the actual student posts and replies. Unlike list_submissions (which shows grading metadata for graded discussions), this downloads the discussion content itself.
Inputs: course_id (required), discussion_id (required), output_dir.
download_submissionsA
Download all submitted files for an assignment to a local directory. Creates a folder per student. Returns the path where files were saved.
Inputs: course_id (required), assignment_id (required), output_dir.
generate_quiz_reportA
Generate a student analysis or item analysis report for a New Quiz. Returns a progress object — poll the returned URL to check when the report file is ready for download.
Inputs: format (required), course_id (required), report_type (required), assignment_id (required).
get_assignmentA
Get full details of a single assignment, including its description/instructions.
Inputs: course_id (required), assignment_id (required).
get_course_activityA
Get daily page views and participation analytics for a course. This returns engagement metrics, not assignment data — use list_assignments for assignment info.
Inputs: course_id (required).
get_course_assignment_analyticsA
Get aggregate statistical analytics per assignment: min/max/median scores, submission counts (on_time, late, missing). This returns statistics, not the assignments themselves — use list_assignments for that. NOTE: this endpoint returns LIFETIME data and does NOT support grading_period_id — for semester-scoped data, fall back to fetching submissions directly via list_submissions.
Inputs: course_id (required).
get_course_schedule_overviewA
Get a chronological overview of all dated assignments, discussions, and quizzes in a course. Useful for understanding the current schedule before making changes.
Inputs: course_id (required).
get_discussionA
Get full details of a discussion topic, including its message/instructions.
Inputs: course_id (required), discussion_id (required).
get_new_quizA
Get full details of a single New Quiz (Quizzes.Next) including settings, time limits, and configuration. The assignment_id is the Canvas assignment ID (found via list_new_quizzes or list_assignments where is_quiz_lti_assignment=true).
Inputs: course_id (required), assignment_id (required).
get_quiz_itemA
Get full details of a single quiz item (question), including its interaction_data, scoring_data, and feedback.
Inputs: item_id (required), course_id (required), assignment_id (required).
get_rubricA
Get full details of a rubric, including all criteria and their rating scales. The returned criterion IDs (e.g. '_7998') are needed by grade_with_rubric. Pass include=['assessments'] to also retrieve every rubric_assessment row (with their IDs) — that's how you find the rubric_association_id and assessment_id needed by update_rubric_assessment / delete_rubric_assessment.
Inputs: course_id (required), rubric_id (required), style, include.
get_rubric_assessmentsA
Get all rubric assessments (grades) for an assignment. Shows how each student was scored on each criterion. Note: this returns the per-criterion data but not the assessment row IDs — for those (needed by update_rubric_assessment / delete_rubric_assessment), call get_rubric with include=['assessments'].
Inputs: course_id (required), assignment_id (required).
get_student_activityA
Get hourly page view breakdown for a specific student in a course.
Inputs: course_id (required), student_id (required).
get_student_assignment_dataA
Get per-assignment scores, submission status, and timestamps for a specific student. This is analytics data — for actual submission details, use list_submissions. NOTE: this endpoint returns LIFETIME data and does NOT support grading_period_id — it includes assignments from all grading periods.
Inputs: course_id (required), student_id (required).
get_student_enrollmentsA
Get enrollment details for a specific student in a course, including grades if available. Pass grading_period_id to get the grade for a specific semester/term instead of the cumulative lifetime grade — find the id with list_grading_periods.
Inputs: course_id (required), student_id (required), grading_period_id.
get_student_summariesA
Get per-student engagement analytics for a course: page views, participations, and tardiness breakdown (missing/late/on_time counts). For enrollment/roster data, use list_students instead. NOTE: this endpoint returns LIFETIME data and does NOT support grading_period_id — the tardiness counts include all assignments since the course began, not just the current semester. For per-semester counts, iterate course submissions with a grading_period_id filter.
Inputs: course_id (required), sort_column.
get_user_profileA
Get any user's profile information including name, email, and bio. Works for students, teachers, and any Canvas user.
Inputs: user_id (required).
grade_submissionA
Grade a single student submission with a score and optional comment. For rubric-based grading, use grade_with_rubric instead. Works for regular assignments, graded discussions (use the assignment_id), and New Quizzes (use the assignment_id).
Inputs: course_id (required), student_id (required), assignment_id (required), score, +4 more.
grade_with_rubricA
Grade a student's submission using a rubric. Provide scores for each criterion. For simple score-based grading without a rubric, use grade_submission instead.
Inputs: course_id (required), student_id (required), assignment_id (required), criterion_scores (required).
hide_gradesA
Hide grades from students for an assignment. Optionally hide for specific students only.
Inputs: course_id (required), assignment_id (required), only_student_ids.
list_assignment_groupsA
List assignment groups (grading categories) in a course with their weights. The returned group IDs are used as assignment_group_id when creating or updating assignments.
Inputs: course_id (required).
list_assignment_overridesA
List all date overrides (section-specific or student-specific) for an assignment. Use this to discover override IDs before updating them.
Inputs: course_id (required), assignment_id (required).
list_assignmentsA
List assignments in a course. This includes regular assignments, graded discussions, and New Quizzes (which are all assignments internally). Returns summary info (id, name, dates, points). Use get_assignment for full details.
Inputs: course_id (required), order_by, search_term, assignment_group_id.
list_calendar_eventsA
List calendar events, optionally filtered by course, date range, or type.
Inputs: type, end_date, course_id, start_date.
list_coursesA
List Canvas courses you have access to. Returns course IDs needed by all other tools. Shows active courses by default. Admins can use search_term to search all courses in the account.
Inputs: search_term, enrollment_state.
list_discussionsA
List discussion topics in a course. Graded discussions also appear as assignments (with assignment_id in the response). To update dates or points of graded discussions, use update_assignment_dates or update_assignment with the assignment_id.
Inputs: course_id (required), search_term, only_announcements.
list_gradeable_studentsA
List students who can be graded for a specific assignment. Use the returned IDs as student_id in grade_submission or grade_with_rubric.
Inputs: course_id (required), assignment_id (required).
list_grading_periodsA
List the grading periods (e.g. semesters, quarters) defined for a course's term. Returns id, title, start_date, end_date, and is_closed for each period. The returned IDs can be passed as grading_period_id to get_student_enrollments and other grade-related tools to scope grades and submissions to a single period instead of the cumulative lifetime grade. Note: schools that don't use grading periods will get a single default period.
Inputs: course_id (required).
list_missing_submissionsA
List all missing assignments for a specific student. Very useful for parent conferences and progress reports.
Inputs: student_id (required), course_id, include_planner_overrides.
list_module_itemsB
List all items in a module.
Inputs: course_id (required), module_id (required).
list_modulesA
List modules in a course. For module management (create, update, delete, add items), see create_module, update_module, add_module_item, and related tools.
Inputs: course_id (required), include_items.
list_new_quizzesA
List all New Quizzes (Quizzes.Next) in a course by filtering assignments. Returns a summary of each. For full details/settings of a single New Quiz, use get_new_quiz. For question management, use list_quiz_items, create_quiz_item, etc.
Inputs: course_id (required).
list_quiz_itemsA
List all items (questions) in a New Quiz. This is for New Quizzes only — Classic Quizzes do not have a question API in this server. Returns each item's ID, position, points, question type, and content.
Inputs: course_id (required), assignment_id (required).
list_rubricsA
List all rubrics in a course. Returns rubric ID, title, point total, and number of criteria.
Inputs: course_id (required).
list_sectionsA
List sections in a course. Optionally include enrolled students.
Inputs: course_id (required), include_students.
list_studentsA
List students enrolled in a course with enrollment-specific data (section, activity, last login). For a simpler user list with any role (teachers, TAs, etc.), use list_users_in_course instead.
Inputs: course_id (required), state, section_id.
list_submissionsB
List all submissions for an assignment (including graded discussions and New Quizzes). Shows student name, score, submission status, and submitted_at timestamp.
Inputs: course_id (required), assignment_id (required), include_comments.
list_termsA
List enrollment terms (semesters/quarters) defined in the account. Returns each term's id, name, and start/end dates. Use the returned id as enrollment_term_id in list_term_courses or create_course.
Inputs: workflow_state.
list_users_in_courseA
List users in a course by role (teacher, student, ta, observer). Simpler output than list_students — use list_students when you need enrollment details like section, activity time, or state.
Inputs: course_id (required), search_term, include_email, enrollment_type.
post_gradesA
Post (make visible) grades for an assignment so students can see them. Optionally post for specific students only.
Inputs: course_id (required), assignment_id (required), only_student_ids.
post_submission_commentA
Add a comment to a student's submission without changing the grade. Useful for leaving feedback during review or asking for revisions. For comments + grade in one call, use grade_submission with the comment field instead.
Inputs: comment (required), user_id (required), course_id (required), assignment_id (required), +1 more.
publish_moduleA
Publish a module (makes it visible to students). Note: this publishes the module container only — individual items retain their own published state.
Inputs: course_id (required), module_id (required).
remove_rubric_from_assignmentA
Remove a rubric association from a specific assignment without deleting the rubric itself.
Inputs: course_id (required), assignment_id (required).
set_quiz_accommodationsA
Set testing accommodations (extra time, extra attempts) for specific students on a New Quiz. Use list_students to find student user IDs.
Inputs: course_id (required), student_ids (required), assignment_id (required), extra_attempts, +1 more.
submission_summaryA
Quick overview of submission status for an assignment — counts of graded, ungraded, and not submitted. For individual submission details, use list_submissions instead.
Inputs: course_id (required), assignment_id (required).
update_assignmentA
Update an existing assignment. Only include fields you want to change. Also works for graded discussions and New Quizzes (via their assignment_id). For date-only changes, prefer update_assignment_dates which is more focused.
Inputs: course_id (required), assignment_id (required), name, due_at, +8 more.
update_assignment_datesA
Update due_at, unlock_at, and/or lock_at for a single assignment. Also works for graded discussions and New Quizzes (which are assignments under the hood). Prefer this over update_assignment when you only need to change dates.
Inputs: course_id (required), assignment_id (required), due_at, lock_at, +1 more.
update_assignment_overrideA
Update dates on a single section/student override. Use list_assignment_overrides first to get the override ID.
Inputs: course_id (required), override_id (required), assignment_id (required), due_at, +2 more.
update_calendar_eventA
Update an existing calendar event. Only include fields you want to change.
Inputs: event_id (required), title, end_at, start_at, +2 more.
update_discussionA
Update a discussion topic's title, message, or published state. Cannot update dates or points — for those, use update_assignment or update_assignment_dates with the discussion's assignment_id (from list_discussions).
Inputs: course_id (required), discussion_id (required), title, message, +1 more.
update_moduleA
Update an existing module. Only include fields you want to change.
Inputs: course_id (required), module_id (required), name, position, +2 more.
update_module_itemA
Update a module item. Only include fields you want to change.
Inputs: item_id (required), course_id (required), module_id (required), title, +3 more.
update_new_quizA
Update a New Quiz's settings (time limit, shuffle, attempts, etc.). For date changes (due_at, unlock_at, lock_at), use update_assignment_dates with the assignment_id instead — New Quizzes are assignments.
Inputs: course_id (required), assignment_id (required), title, published, +7 more.
update_quiz_itemA
Update an existing question (item) in a New Quiz. Only include fields you want to change. Commonly used after create_quiz_item to set the correct answer IDs in scoring_data once the choice IDs are known.
Inputs: item_id (required), course_id (required), assignment_id (required), title, +7 more.
update_rubricA
Update an existing rubric's title, criteria, or display settings. Changes apply to all assignments using this rubric. If you change only the title (without passing criteria), existing criteria are preserved automatically.
Inputs: course_id (required), rubric_id (required), title, criteria, +1 more.
update_rubric_assessmentA
Edit an existing rubric assessment (e.g. correct one student's rubric grade) without re-grading the whole submission. Find rubric_association_id and assessment_id by calling get_rubric with include=['assessments']. For most grading workflows, grade_with_rubric is simpler — use this tool when you specifically need to surgically edit one row.
Inputs: course_id (required), assessment_id (required), criterion_scores (required), rubric_association_id (required), +1 more.
update_rubric_associationA
Update the display/grading settings of an existing rubric–assignment association without re-associating. Use this to toggle 'Remove points from rubric' (hide_points), hide the score total, or change use_for_grading. Find the association_id by calling get_rubric (look at assignment_associations) or by reading the assignment's rubric_settings.
Inputs: course_id (required), association_id (required), hide_points, use_for_grading, +2 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 80 tools
Most tools target distinct resources and actions, with clear descriptions separating similar-sounding ones (e.g., list_students vs list_users_in_course vs list_gradeable_students). However, the sheer volume of analytics and listing tools (get_student_activity, get_course_activity, get_student_summaries, get_student_assignment_data) creates some potential for misselection despite distinct descriptions.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., list_calendar_events, create_module, update_assignment, delete_rubric). There are no camelCase or mixed conventions, and multi-word verbs like batch_update are uniform across the set.
With 80 tools, this is far beyond the typical well-scoped range (3-15) and even beyond the 'heavy' threshold of 25+. While the Canvas domain is broad, this many tools creates an overwhelming surface, and many tools could be consolidated (e.g., separate date-update tools, multiple student-listing tools).
The set covers core workflows for assignments, quizzes, discussions, modules, rubrics, and submissions, but there are notable gaps: several descriptions reference tools like create_course, list_term_courses, and list_outcomes that are not present. This forces reliance on other MCPs, making the surface feel incomplete on its own.
Maintenance
Related MCP Connectors
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
One MCP server for the services your AI needs: memory, files, Microsoft 365, kanban and more.
MCP server that lets your AI assistant build and deploy apps, hosting each one at a live URL.
MCP server that lets AI assistants use all OneSchema features exposed via the public API.
Related MCP Servers
- AlicenseAqualityBmaintenanceMCP server for Canvas LMS, providing 115+ tools to read courses, assignments, submissions, rubrics, quizzes; grade, comment, manage course content, and handle Canvas admin workflows from any AI agent.185916 npm10MIT
- AlicenseNot gradedqualityDmaintenanceA local MCP server for Canvas LMS that enables querying courses, assignments, grades, modules, and more from any MCP-compatible AI client.11 npmMIT
- FlicenseNot gradedqualityDmaintenanceMCP server for Canvas LMS that exposes courses, assignments, modules, pages, files, grades, and submissions as tools for AI agents.-
- AlicenseNot gradedqualityDmaintenanceA teacher-facing MCP server that wraps the Canvas LMS REST API, enabling AI assistants to create and manage course content across multiple Canvas courses.11 npm1MIT