Skip to main content
Glama

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

src/servers/core.ts

The 79 daily teaching/grading tools + the describe_canvas_mcps meta tool

Admin MCP entry point

src/servers/admin.ts

The 18 course/section/enrollment lifecycle tools

Extras MCP entry point

src/servers/extras.ts

The 36 outcomes/groups/pages/files/messaging/late-policy/classic-quizzes tools

CLI dispatcher

src/cli.ts

npx canvas-agent starts the core server; setup/reveal/vault-gc subcommands stay on the same bin. The two extra bins (canvas-agent-admin, canvas-agent-extras) point directly at their server files.

Canvas API client

src/canvas-client.ts

Thin fetch wrapper with automatic pagination (canvasAll for flat array endpoints, canvasAllWrapped for {key: [...], linked: {…}} shapes) and rate-limit backoff. Pipes every response through anonymizer → name-detector → sandbox before returning.

Tool modules

src/tools/*.ts

One file per Canvas domain. Mixed-bucket files export per-bucket registrars (e.g. registerCoursesCore + registerCoursesAdmin); single-bucket files export one (e.g. registerAssignmentsCore).

Privacy pipeline

src/anonymizer.ts, src/name-detector.ts, src/sandbox.ts, src/vault.ts

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 ~/.canvas-agent/vault/.

Setup wizard

src/setup.ts

Interactive CLI that validates credentials, detects Claude Code / Desktop / Antigravity CLI, and registers all three v2 bins.

Tool-routing assertion harness

scripts/assert-tool-routing.mjs

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 npm test.

Landing site

docs/

Static GitHub Pages site with the end-user setup guide

Tool modules

Module

File

v2 bin(s)

Covers

Courses

courses.ts

core + admin

core: list courses, terms, assignment groups, modules, grading periods. admin: create/update/delete/conclude/reset/copy course, navigation tabs.

Assignments

assignments.ts

core

CRUD assignments, batch update dates

Submissions

submissions.ts

core

List/download submissions, download discussion entries

Grading

grading.ts

core + extras

core: grade/bulk-grade/post/hide, missing & gradeable students. extras: late policy, grading standards.

Rubrics

rubrics.ts

core

CRUD rubrics, copy across assignments/courses, associate with display toggles, link to outcomes, view/edit/delete assessments

Outcomes

outcomes.ts

extras

List outcomes/groups, outcome results, mastery rollups

Modules

modules.ts

core

CRUD modules and module items, publish modules

Pages

pages.ts

extras

CRUD pages, front page, page revisions

Discussions

discussions.ts

core

CRUD discussions and batch updates (download entries lives in submissions.ts)

Quizzes (Classic)

quizzes.ts

extras

List/get/update Classic Quizzes

New Quizzes

new-quizzes.ts

core

List/CRUD New Quizzes, quiz items, accommodations, generate quiz reports

Calendar

calendar.ts

core

CRUD calendar events

Files

files.ts

extras

List/get/update/delete files, folders, quota

Enrollments

enrollments.ts

core + admin

core: list students/sections/users, get profile. admin: crosslist, create/update/delete sections, enroll/drop users, move student.

Communication

communication.ts

core + extras

core: post submission comment. extras: send_message, create_announcement.

Groups

groups.ts

extras

Group sets, groups, membership, auto-distribute

Analytics

analytics.ts

core + extras

core: course/student activity, assignment analytics, student summaries. extras: messaging data.

Scheduling

scheduling.ts

core + extras

core: assignment dates, batch updates, overrides, schedule overview. extras: classic-quiz dates.

Meta

meta.ts

core

describe_canvas_mcps — explains the three-MCP architecture to the AI

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

add_user_to_group

canvas-agent-extras

auto_distribute_unassigned

canvas-agent-extras

conclude_course

canvas-agent-admin

copy_course_content

canvas-agent-admin

create_announcement

canvas-agent-extras

create_course

canvas-agent-admin

create_folder

canvas-agent-extras

create_group

canvas-agent-extras

create_group_set

canvas-agent-extras

create_page

canvas-agent-extras

create_section

canvas-agent-admin

crosslist_section

canvas-agent-admin

decrosslist_section

canvas-agent-admin

delete_course

canvas-agent-admin

delete_enrollment

canvas-agent-admin

delete_file

canvas-agent-extras

delete_page

canvas-agent-extras

delete_section

canvas-agent-admin

enroll_user

canvas-agent-admin

get_file

canvas-agent-extras

get_file_quota

canvas-agent-extras

get_front_page

canvas-agent-extras

get_grading_standards

canvas-agent-extras

get_late_policy

canvas-agent-extras

get_outcome

canvas-agent-extras

get_outcome_rollups

canvas-agent-extras

get_page

canvas-agent-extras

get_quiz

canvas-agent-extras

get_student_messaging_data

canvas-agent-extras

list_course_files

canvas-agent-extras

list_course_tabs

canvas-agent-admin

list_folders

canvas-agent-extras

list_group_categories

canvas-agent-extras

list_groups

canvas-agent-extras

list_outcome_groups

canvas-agent-extras

list_outcome_results

canvas-agent-extras

list_outcomes

canvas-agent-extras

list_page_revisions

canvas-agent-extras

list_pages

canvas-agent-extras

list_quizzes

canvas-agent-extras

list_term_courses

canvas-agent-admin

move_student_to_section

canvas-agent-admin

remove_user_from_group

canvas-agent-extras

reset_course_content

canvas-agent-admin

send_message

canvas-agent-extras

set_late_policy

canvas-agent-extras

update_course_navigation

canvas-agent-admin

update_course_settings

canvas-agent-admin

update_enrollment_state

canvas-agent-admin

update_file

canvas-agent-extras

update_page

canvas-agent-extras

update_quiz

canvas-agent-extras

update_quiz_dates

canvas-agent-extras

update_section

canvas-agent-admin

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 routing

npm run dev starts tsc --watch for iterating on tool modules.

Adding a tool

  1. Decide which bucket it belongs to (core / admin / extras) — see V2_BUILD_PLAN.md for the rationale on existing tools.

  2. Add the server.tool(...) registration to the appropriate register*Core / register*Admin / register*Extras function in src/tools/<domain>.ts. Create a new domain file + registrar if needed; export from the file and import/call in the matching src/servers/<bucket>.ts.

  3. Update the routing manifest in scripts/assert-tool-routing.mjs if the tool lands in admin or extras.

  4. npm test to verify.

  5. 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:

  1. 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.

  2. 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.

  3. 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 detail

vault-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_term queries hit Canvas's real-name index. If the AI sends a token, Canvas finds nothing — reveal offline and search by user_id instead.

  • download_submissions writes 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 /conversations lists) 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_id to /courses/{id}/enrollments (returns per-period current_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_periods returns a wrapped response — {"grading_periods": [...], "meta": {...}} — so the canvasAll pagination helper won't flatten it. Use canvas and unwrap manually (see list_grading_periods in tools/courses.ts).

  • Analytics endpoints don't support grading_period_id — get_student_summaries, get_course_assignment_analytics, and get_student_assignment_data always return lifetime totals. For semester-scoped data, fetch submissions directly with grading_period_id.

License

MIT

Available Tools

80 tools
add_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:

  1. "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.

  2. "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.

  3. "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>"] }

  4. "essay" (Essay / Free Response) interaction_data: {} scoring_data: { "value": "" }

  5. "file-upload" (File Upload) interaction_data: {} scoring_data: { "value": "" }

  6. "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" }] }

  7. "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>"] }

  8. "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" }] }

  9. "numeric" (Numeric Answer) interaction_data: {} scoring_data: { "value": "42" } or { "value": { "exact": 42, "margin": 0.1 } }

  10. "fill-blank" (Fill in the Blank) interaction_data: {} scoring_data: { "value": ["acceptable answer 1", "acceptable answer 2"] }

  11. "rich-fill-blank" (Fill in Multiple Blanks) interaction_data: { "blanks": [{ "id": "b1", "item_body": "blank1" }] } scoring_data: { "value": { "b1": ["answer1", "answer2"] } }

  12. "formula" (Formula / Calculated) interaction_data: { "formula": "x + y", "variables": [{ "name": "x", "min": 1, "max": 10 }] } scoring_data: { "value": { "formula": "x + y", "margin": 0.01 } }

  13. "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

    A3.7/5.0

    Scored across 80 tools

    Disambiguation4/5

    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.

    Naming Consistency5/5

    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.

    Tool Count2/5

    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).

    Completeness3/5

    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

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers