canvas-teacher-mcp
This server automates Canvas LMS instructor tasks: it reads courses, assignments, and quizzes; builds assignment pages and quizzes; posts announcements (with preview); runs a staged grading workflow (propose rubric → machine grading → post grades); and provides global skills for GitHub coding assignments, Google Docs, module overviews, and publisher quiz banks, all while never deleting or publishing content directly.
Setup & Configuration: Register schools and courses by URL, manage course configs, list registered courses, and retrieve course coordinates (Canvas ID, base URL, output paths).
Reading & Managing Content: Fetch and list pages, modules, assignments, quizzes, quiz questions, students, submissions, rubrics, assignment groups, and extract/classify links from Canvas HTML.
Creating & Updating Content: Create and update pages, assignments (due dates, points), modules, module items, quizzes (time limits, attempts), and quiz questions. Set due dates across multiple assignments. All new content is unpublished by default.
Specialized Content Generation: Build coding assignment pages (GitHub-backed specs), notebook assignment pages, weekly agendas, module overviews, formatted Google Docs, and quizzes from plain-text publisher test banks.
Announcements: Preview before sending; post only after explicit confirmation.
Grading Workflow: Identify assignments needing grading; list/submissions (with attachments, classification); read assignment instructions as students saw them; propose rubrics; run machine grading (Stage A, scores only); post grades and comments (dry-run default, explicit confirmation required). Fix mode for correcting errors. Supports grading of notebook and GitHub coding assignments.
GitHub & Google Workspace Integration: Create GitHub coding assignment repos (solution, tests, starter), format Google Docs and Slides, read/format Google Docs via CLI.
Direct API Access: Call any Canvas API endpoint (DELETE blocked) for uncovered functionality.
Safety Constraints: No content deletion; no publishing of created content by default; no arbitrary code execution; credentials stored locally; explicit confirmation for destructive or sensitive actions.
Allows reading and writing Canvas LMS course content: courses, modules, assignments, quizzes, pages, announcements, and submissions, with support for authentication and course setup.
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-teacher-mcp Create an assignment for next Tuesday in my Economics course."
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-teacher-mcp
An MCP server for Canvas LMS, from the instructor's side. Ask your assistant to read a course, build an assignment page or a quiz, post an announcement, or run a grading pass — it calls Canvas for you.
v0.1.0. Everything is created unpublished and nothing is ever deleted.
Install
Point your MCP client at it. Nothing to install by hand — uvx fetches it on first run.
{
"mcpServers": {
"canvas-teacher": {
"command": "uvx",
"args": ["canvas-teacher-mcp"],
"env": { "CANVAS_LMS_ROOT": "/absolute/path/to/your/teaching/folder" }
}
}
}Claude Desktop — Settings → Developer → Edit Config opens the file. Add the entry inside the
existing mcpServers object rather than replacing it, then quit and reopen the app. A GUI app does
not inherit your shell PATH, so if the server does not appear, give the full path to uvx
(which uvx will tell you).
Claude Code — the same JSON in .mcp.json at your project root. Servers attach when a session
starts, so open a new one.
Codex — ~/.codex/config.toml, TOML rather than JSON, with the environment in a table of its
own:
[mcp_servers.canvas-teacher]
command = "uvx"
args = ["canvas-teacher-mcp"]
[mcp_servers.canvas-teacher.env]
CANVAS_LMS_ROOT = "/Users/you/Teaching"Use a plain chat or the codex CLI: inside a Codex Desktop project, no MCP tools appear at
all, while codex mcp list still shows the server — which makes it read as a setup mistake when
it is not (openai/codex #25843).
CANVAS_LMS_ROOT is the one thing you choose: the folder your courses live in. It is required
— the server keeps no root of its own, so this declaration is the only place it is written, and
you can always see what it is. Leave it out and the server says so on connect, telling your
assistant which file to add it to.
The folder need not exist yet; setup creates what it needs. An environment already exporting
CANVAS_LMS_ROOT works too — the server just reads the environment, and does not care how a
value got there.
Updating. uvx remembers which versions exist, not only the ones it downloaded, so a new
release can go unnoticed. To pick one up, either run it once with --refresh-package:
uvx --refresh-package canvas-teacher-mcp canvas-teacher-mcpor put those two arguments in front of the package name in the declaration above, and the check
happens every time your client starts it. (uv cache clean canvas-teacher-mcp does not do
this — it removes the downloaded package and keeps the stale list of versions.)
To try a change before it is released, point at the repository instead:
"args": ["--from", "git+https://github.com/Canvas-LMS-MCP/canvas-teacher-mcp", "canvas-teacher-mcp"]
Related MCP server: Canvas Agent
First run
Say "set up Canvas". Setup answers one step at a time; you relay what it asks for.
you set up Canvas
setup course root: /Users/you/Teaching
skills: read from this package
workflow: read from this package
schools: none registered
Next: what is your Canvas address? e.g. https://myschool.instructure.com
you https://myschool.instructure.com
setup Created /Users/you/Teaching/.claude/Canvas-Auth/myschool.json
Two ways to finish, and the first keeps the token out of this conversation:
1. Open that file and paste the token into its empty "token" field,
then ask me to run setup again — I will verify it.
2. Tell me the token and I will store it. It will then live in this
conversation's record as well as the file.
The token comes from Canvas: Account -> Settings -> + New Access Token.The file it made:
{
"base_url": "https://myschool.instructure.com/api/v1",
"token": ""
}Paste your token between those quotes, save, and say "run setup again":
setup schools: myschool
myschool: signed in as Your NameA token that Canvas rejects is never stored, and a token already stored is never overwritten.
No token at your school? Some run SSO only. Say so — the server opens a browser once, you log in as usual, and the session is saved and refreshed from then on.
Add a course
Give the assistant the course's Canvas URL.
you add this course: https://myschool.instructure.com/courses/12345
setup Registered Intro to Programming as slug 'cs101'.
Config: /Users/you/Teaching/CS101/.claude/course-config/cs101.json
School: myschool (guessed from the domain — say so if it is wrong)
Tools now take course='cs101'.It read the course's own name and code from Canvas; the slug and the folder are proposals. To put it somewhere else, say so: "add it under Fall2026/CS101".
The config is two lines, because the rest is derived:
{
"canvas_url": "https://myschool.instructure.com/courses/12345",
"school": "myschool"
}course_id, base_url, domain and the token variable all come from that URL. Add more only
when a feature needs it: github_org for GitHub assignments, db_path for grading records,
drive_folder for Google Docs, output_dir to write somewhere other than the default.
Registering is for convenience — it is what lets tools take course='cs101' instead of an id.
Authentication is per SCHOOL, so any course on that domain is reachable by id without registering.
Where things end up
<ROOT>/
├─ .claude/
│ ├─ Canvas-Auth/<school>.json your credentials — never leaves this machine
│ ├─ skills/ (optional) the methods, if you copy them to edit
│ └─ CourseGlobalWorkflow/ (optional) the working rules, same
└─ AVC/ one folder per school
└─ CS101/
└─ .claude/
├─ course-config/cs101.json the course's coordinates
├─ input/ material you bring in
└─ output/<kind>/ everything the server writesRegistering a course proposes <school>/<course>; pass course_dir for anything else, and any
depth works — a school whose departments are separate can put a level between them.
Credential files are written owner-only, and an existing world-readable one is corrected the next
time setup runs. Keep Canvas-Auth/ out of git: one token in a history is a token to revoke.
Skills and the working rules need no copying. They are read from inside the package and work as they are. Copy them into your tree only when you want to CHANGE them — grading policy, late grace, rubric splits, the tone of a comment. The packaged copies are replaced on every upgrade, so an edit there is lost; an edit in your tree survives.
What it does
Read — courses, modules and their items, assignments, quizzes and questions, pages, submissions with their attachments fetched and read (PDF, images, Office files, notebooks), students, and every link or embed inside a page, module or quiz.
Write — pages, modules, assignments, quizzes and their questions, due dates, module items. An announcement is previewed first and sent only when you say so.
Build — a coding assignment page from a spec, a notebook assignment page, a weekly agenda, a module overview, a formatted Google Doc, a quiz from a plain-text question bank, and a student starter repository from a solved assignment.
Grade — read the assignment as the student saw it, propose the rubric, run the machine pass, and post the result when you ask for that separately. A grading run stops at a report; posting is its own step, defaults to a dry run, and refuses to post evidence that was never read.
Anything else — canvas_api_request calls any Canvas endpoint the tools above do not cover.
What it will not do
Delete. No tool removes a page, an assignment, a submission or a course, and the direct API call refuses DELETE.
Publish. Everything is created unpublished. Publishing stays yours.
Run arbitrary code. There is no shell here, and no
run_python.
Notes that will save you a morning
The Canvas API answers 200 to several calls that change nothing. This server sends the forms Canvas actually accepts:
a grade must be form-encoded; as JSON it returns 200 and sets nothing
a quiz-question update needs the FULL payload, or it applies nothing
question_countstays cached until the quiz is touched againseconds_late_overrideis ignored when sent withlate_policy_statussubmission comments render HTML in SpeedGrader, but the API returns them flattened — the API response is not proof of what the student sees
Requirements
Python 3.10+, which uvx provides. A school without API tokens also needs Playwright's Chrome,
installed on the first browser login. GitHub assignment tools need git and gh; Google Docs
need the gws CLI.
License
MIT.
Available Tools
58 toolsadd_module_itemB
Add an item to a module, unpublished.
item_type is Canvas's own: Page, Assignment, Quiz, File, Discussion, ExternalUrl,
SubHeader. A Page item needs page_url; Assignment/Quiz/File need content_id.
Inputs: title (required), course (required), item_type (required), module_id (required), +2 more.
add_quiz_questionsA
Add or update questions. A question already carrying the same name is updated in place.
Each question is {"name", "type", "text", "points", ...} where type is one of:
multiple_choice choices: list[str] correct: index
multiple_answers choices: list[str] correct: list[index]
true_false correct: true | false
essay (no extra fields)
text is HTML.
Inputs: course (required), quiz_id (required), questions (required).
agenda-wrapupA
GLOBAL — generate the weekly Agenda (week start) and Wrap-up (week end) Canvas pages for a module, from the same module data. Config-driven per course (course_slug -> course_config). Triggers: 'week N agenda', 'wrap-up for week N', 'update the agenda', 'make the week 3 agenda/wrapup'.
Inputs: no named parameters. Returns: result
assignment-page-builderA
GLOBAL methodology for building a Canvas ASSIGNMENT/LAB page from the universal skeleton canvas_core/assignment_page_builder.py. The skeleton is the CODE (machinery); this skill is the HOW (authoring method + finalize order). Per-course skills (e.g. customize-assignment-page = git plugin, jshell-lab = jshell plugin) supply the course config + content and reuse this. Policy (grading %, published, dates) lives in CourseGlobalWorkflow and is only REFERENCED here. Use when building/updating any Canvas assignment or lab page.
Inputs: no named parameters. Returns: result
build_coding_assignment_pageA
Build the Canvas page for a programming assignment whose starter repo is on GitHub.
assignment carries the content: code, title, gist, spec, restrictions, elaboration,
test_items, and either prototype + params + returns (a function to write) or
input + output + expected (a program reading stdin). Read the git-asmt-page skill
before filling it — the field list and the section order are its subject.
Returns the rendered HTML; with publish_to_canvas it also creates the Canvas assignment.
Inputs: course (required), points (required), assignment (required), due_at, +2 more.
build_notebook_assignment_pageA
Build the Canvas page for a Colab/Jupyter notebook assignment.
lab describes the notebook. The rubric TEXT is derived from the notebook itself; only the
weight split is a default. Read the nb-homework-create skill first.
Inputs: lab (required), course (required), due_at, points, +1 more.
build_rich_docA
Build a formatted Google Doc — banners, section boxes, callouts, coloured code blocks.
blocks is the document's content in the generator's block form; read the gws-richdoc
skill for the shapes. folder_id is a Drive folder; omitted, the doc lands in the default
location and the answer says where.
Needs the gws CLI on this machine; without it the call fails with that message rather than
producing a broken document.
Inputs: name (required), blocks (required), folder_id.
classify_submissionsB
Split the submissions into graded / resubmitted / new / not submitted.
Inputs: course (required), assignment_id (required).
create-announcementA
GLOBAL, config-driven — generate a weekly Canvas announcement from a module's contents for ANY course. Use when the user says make/write the weekly announcement, week N announcement, or announce this week. Reads the module, summarizes what to read/watch/do/submit, lists graded items with due dates, and closes warmly. Course coordinates come from course_config.load(<course_slug>) (course_id, school, token) — nothing hardcoded. PREVIEW-first; sends emails only on the instructor's explicit go. Invoke with the course_slug + week or module id.
Inputs: no named parameters. Returns: result
create_assignmentB
Create an assignment, unpublished. due_at is ISO-8601 UTC.
Inputs: name (required), course (required), due_at, description, +2 more.
create_moduleC
Create a module, unpublished.
Inputs: name (required), course (required).
create_pageC
Create a page, unpublished.
Inputs: body (required), title (required), course (required).
create_quizA
Create an empty quiz, unpublished. due_at is ISO-8601 UTC, time_limit is minutes.
Inputs: title (required), course (required), due_at, time_limit, +3 more.
extract_linksC
Every link in a block of Canvas HTML, classified by kind.
Inputs: html (required).
finalize_quizA
Rewrite the description summary and refresh the quiz's stale counts.
Canvas leaves question_count and points_possible stale after any question change, so this
runs after the questions are in.
Inputs: course (required), quiz_id (required), intro_html.
get_assignmentC
One assignment, description included.
Inputs: course (required), assignment_id (required).
get_courseB
A course's coordinates: Canvas id, base url, school, GitHub org, output paths.
Never returns a secret — canvas_token_env names the variable, it is not the token.
Inputs: course (required).
get_docA
Read a workflow document, e.g. GRADING.md or Access/Canvas.md.
path is relative to CourseGlobalWorkflow/.
Inputs: path (required). Returns: result
get_moduleD
One module.
Inputs: course (required), module_id (required).
get_pageC
One page, body included. slug is the page's url segment.
Inputs: slug (required), course (required).
get_quizD
One quiz: title, description, question count, points.
Inputs: course (required), quiz_id (required).
get_rubricB
The assignment's Canvas rubric object, when it has one.
The rubric a student was shown outranks this — an assignment page carries its own table.
Inputs: course (required), assignment_id (required).
get_submissionA
One submission in full, body and attachments included.
Inputs: course (required), user_id (required), assignment_id (required).
git-asmtA
GLOBAL L1 ENTRY POINT (dispatcher) for creating a GitHub coding assignment end-to-end. Routes to two children: git-asmt-repo (build the solution/tests + prove 100/100 + ship the Starter + register in the org-hub) and git-asmt-page (build the Canvas assignment page via git_page). Language-agnostic; the language mechanics are L2 (git-asmt-repo/languages/*) and the course coordinates are the L3 course wrapper (config). Use when the user says 'make/build/create assignment ' — this decides repo-first then page.
Inputs: no named parameters. Returns: result
git-asmt-pageA
GLOBAL L1 child of git-asmt — build the Canvas ASSIGNMENT PAGE for a git coding assignment via the global git_page (assignment-page-builder). Your job = fill the asmt dict well (gist, spec, I/O = function contract, examples call→output, restrictions, elaboration, test-items table, per-item points/rubric, per-item guide, function prototype+params) → git_page(course_slug, asmt). Language-agnostic; which fields to use (stdin-program vs function) comes from the L3 course wrapper's curriculum. Use to make/renew any git-assignment Canvas page. Canvas side ONLY — the repo is git-asmt-repo.
Inputs: no named parameters. Returns: result
git-asmt-repoA
GLOBAL, language-agnostic L1 abstract for building + testing a GitHub coding-assignment repo through the org-hub autograder. Owns the WHAT (audit → instruction-fidelity harness → prove 100/100 → ship the Starter → gates) with NO language mechanics. The HOW-to-compile/run/assert is delegated to an L2 language skill (git-asmt-repo/languages/*), and the course coordinates come from an L3 course wrapper (config). Use as the shared core every course's git build/test wrapper points to. NEVER re-implement this per course.
Inputs: no named parameters. Returns: result
gradeA
GLOBAL step-by-step grading skill. The ONE ordered procedure for grading ANY course's Canvas assignment OR quiz/exam through the shared grade engine — Stage A (engine, no post) → Stage B (AI review in chat) → report → pre-post self-challenge → POST (instructor go + post-gate). Bundles the canonical policy (GRADING.md — Part D is the quiz/exam half), the flow (skills/grade/SKILL.md), the layer map (CourseGlobalWorkflow/README.md), and the engine contracts (GradingEngine/*) into one sequential runbook, and ships the runnable Stage-A driver grade_skill.py. Invoke BEFORE any grading work — never grade ad-hoc.
Inputs: no named parameters. Returns: result
grade-git-programA
Grading SUB-SKILL for git-program assignments AND git-program quiz questions (the M-series coding items) — the type-specific plug-in of the global grade skill, analogous to grade-nb. ONE skill for both: internally a quiz question is graded STRICTER (quiz-exam-policy) and a homework LOOSER. Runs THROUGH THE ENGINE (core.grade → graders/gh) + GRADING Part B; reads the build-time grading info left by git-homework / quiz-builder. STATUS: STUB — full setup at first grading.
Inputs: no named parameters. Returns: result
grade-nbA
NB (Colab / Jupyter notebook) grading SUB-SKILL — the type-specific plug-in for the global grade skill. When an assignment's submission is a Colab/Drive notebook, grade dispatches HERE for the notebook + revision-history inspection, then returns to the general flow (report → self-challenge → POST). Consolidates GRADING.md Part C + GradingEngine/NbInspect.md into concrete steps. The NB grading RUNS THROUGH THE ENGINE (core.grade → graders/nb.py + nb_inspect) — this skill is the METHOD, not a standalone driver. Master is skills/grade/SKILL.md.
Inputs: no named parameters. Returns: result
gslides-formatD
The gslides-format skill document.
Inputs: no named parameters. Returns: result
gws-docA
Read and format Google Docs using gws CLI. Use when reading a Google Doc's content, or creating/reformatting a Google Doc with proper heading styles, bold text, or structured content.
Inputs: no named parameters. Returns: result
gws-richdocA
Create a rich-format Google Doc (banner, color section boxes, navy step badges, tip/info/warning callouts, dark syntax-colored code blocks, bullets) DETERMINISTICALLY via the fixed generator build.py. Use when the user asks for a "gws-richdoc / rich-gdoc" doc or a polished, visually-structured Google Doc. ALWAYS run build.py — never hand-author the HTML (that is what made every session look different).
Inputs: no named parameters. Returns: result
list_assignment_groupsD
Assignment groups and their weights.
Inputs: course (required). Returns: result
list_assignmentsB
Every assignment: id, name, points, due date, published state.
Inputs: course (required). Returns: result
list_coursesB
Every course slug registered in the course root.
Inputs: no named parameters. Returns: result
list_module_itemsC
What is inside a module, in order.
Inputs: course (required), module_id (required). Returns: result
list_modulesC
Every module: id, name, position, published state.
Inputs: course (required). Returns: result
list_pagesA
Every page in the course: title, url slug, published state.
Inputs: course (required). Returns: result
list_quiz_questionsB
Every question on a quiz: id, name, type, points.
Inputs: course (required), quiz_id (required). Returns: result
list_studentsC
Active students: id, name, email.
Inputs: course (required). Returns: result
list_submissionsC
Who submitted what: user id, submitted_at, current score, attempt count.
Inputs: course (required), assignment_id (required). Returns: result
module-overview-pageA
GLOBAL, config-driven — build a module OVERVIEW page (the representative page at the top of a Canvas module): 📌 Overview (the plan) + an optional slide embed + FLEXIBLE SECTION BLOCKS grouping that module's items (readings/videos/quizzes/assignments) as a roadmap. Categories are DATA — add/remove freely per course, no fixed columns, no wrappers needed. Renderer = module_overview.py (coords from course_config.load(<course_slug>)). For per-slide breakdowns it uses the slide-plan skill. Triggers: 'module overview page', 'make the overview/representative page for module N', '대표 페이지'.
Inputs: no named parameters. Returns: result
nb-homework-createA
Create/prepare an NB (Colab / Jupyter) homework TEMPLATE so it can be graded cleanly by the grade-nb sub-skill. Embeds a hidden per-cell ANCHOR in every instruction + provides a matching pre-filled ANSWER cell, structures the notebook into sections with a per-section pin + an essay reflection, and bakes the student "do not delete the cells" guidance. The creation and grading sides are mirror images — the grader anchors on exactly what this skill stamps. Global; pairs with skills/grade-nb.
Inputs: no named parameters. Returns: result
needs_gradingC
Assignments with submissions waiting to be graded.
Inputs: course (required), only_open. Returns: result
post_gradesA
Write the rendered grades and comments to Canvas. Its own step, asked for on its own.
grades_json is the POST-READY file the report render produced — a Stage-A file is refused.
The default is a dry run that reports what would be written; pass dry_run=false to write.
fix is for correcting an earlier mis-grade: it is the only mode that deletes a comment, and
only the one this poster recorded for the current attempt.
A post aborts when any evidence the engine surfaced was never read.
Inputs: grades_json (required), fix, dry_run. Returns: result
preview_announcementA
Render what would be sent, and say how to send it. Sends nothing.
Inputs: title (required), course (required), message (required).
propose_rubricC
The rubric the engine reads for this assignment, for the instructor to approve.
Priority is the instruction sheet first, then the Canvas rubric object, then the default — a proposal, never an applied decision.
Inputs: code (required), course (required), grader.
publisher-bank-quizA
GLOBAL — turn a publisher's plain-text question bank (Liang/Pearson test bank, one chapter per file) into a Canvas CLASSIC quiz. Parses the bank into quiz_builder's question JSON, renders a preview HTML for review, then delegates the Canvas write to quiz-builder. Multiple-choice and multiple-answer items; per-question points are an input. Use when the user has a chapter test-bank .txt (or .docx text) and wants it as a Canvas quiz. Triggers: 'publisher bank', 'test bank', 'chapter N quiz from the bank', '뱅크로 퀴즈'.
Inputs: no named parameters. Returns: result
quiz-builderA
GLOBAL methodology for building/updating a Canvas CLASSIC quiz — its question items + the description summary. Create a quiz from nothing OR modify an existing one. Dispatches question items by type (native MCQ/T-F/essay/fill-in via the Quizzes API; a git-program question defers to the course-local git-homework). All Canvas quiz API calls go through the co-located quiz_builder.py — never hand-rolled. Use when making/updating any Canvas quiz's questions or details.
Inputs: no named parameters. Returns: result
read_assignment_instructionsA
The assignment as the STUDENT saw it — description, rubric, due date, attachments.
Grading is against what the student read, so this comes before any scoring.
Inputs: code (required), course (required).
readytogoA
Generic session orientation. Loads account + course global rules and detects the active course from the current working directory. For project-specific orientation, run from inside a project dir — the per-course readytogo.md takes precedence over this one.
Inputs: no named parameters. Returns: result
run_stage_aA
Run Stage A: collect every submission, score what a machine can, and save the artifacts.
Returns the engine's result — per-student scores and the evidence it surfaced. It posts nothing and it writes no comment; the wording is Stage B's, done in conversation, and the post is a separate authorised step.
Inputs: code (required), course (required), rubric.
send_announcementB
Post an announcement. Requires confirm='SEND', which the preview explains.
Inputs: title (required), course (required), confirm (required), message (required).
set_due_datesC
Set one due date on several assignments. due_at is ISO-8601 UTC.
Inputs: course (required), due_at (required), assignment_ids (required).
setupA
Set this install up, one step per call. Relay the answer to the instructor.
Call with no arguments to see where things stand. Pass canvas_url to register a SCHOOL —
that writes the config with an empty token and reports the file to paste one into; pass
token as well only if the instructor prefers that, since the token then stays in this
conversation's record. Pass course_url to register a COURSE, optionally overriding the
proposed slug and course_dir.
Inputs: slug, token, canvas_url, course_dir, +1 more. Returns: result
slide-planA
GLOBAL sub-skill of module-overview-page — turn a multi-slide module into one SECTION per slide: 'this slide covers X → do these assignments/labs based on it', with the slide deck embedded in that section. Returns section tuples that module-overview-page's make_page consumes. Use when a module has SEVERAL slide decks and you want each slide's content summarized next to the tasks derived from it. Triggers: 'slide plan', 'per-slide breakdown', 'slide N covers … do …'.
Inputs: no named parameters. Returns: result
update_assignmentC
Update an assignment. Publish state is left alone.
Inputs: course (required), assignment_id (required), name, due_at, +2 more.
update_pageA
Update a page's title and/or body. Publish state is left alone.
Inputs: slug (required), course (required), body, title.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 58 tools
While many tools have clear distinct purposes, there are several clusters with overlapping responsibilities, such as the grading skills (grade, grade-git-program, grade-nb), page builders (assignment-page-builder, git-asmt-page, build_coding_assignment_page), and document formatters (gws-doc, gws-richdoc, gslides-format). Descriptions help differentiate them, but an agent could still mis-select in these areas.
Tool names mix snake_case (list_courses, get_page) with kebab-case (agenda-wrapup, assignment-page-builder) and even a verb-less noun style (git-asmt-repo, quiz-builder). Verb prefixes are inconsistent (read vs get vs list, create vs build vs add), making the naming pattern unpredictable.
With 58 tools, the server far exceeds the typical well-scoped range of 3-15 and even the 25+ threshold for excessive. The large number likely reflects an integrated suite of skills and utilities, but it risks overwhelming agents and increasing selection errors.
The tool surface covers a comprehensive teaching workflow: assignments, quizzes, pages, modules, announcements, submissions, grading, and Google Docs. Minor gaps exist, such as no delete operations for most resources and no list/get for announcements, but the core lifecycle is well represented.
Related MCP Connectors
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.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Educational MCP server with 17 math/stats tools, visualizations, and persistent workspace
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA local MCP server for Canvas LMS that enables querying courses, assignments, grades, modules, and more from any MCP-compatible AI client.14 npmMIT
- AlicenseAqualityDmaintenanceMCP server that connects AI assistants to Instructure Canvas LMS, enabling teachers and administrators to manage courses, assignments, grades, and more through natural language.8022 npm1MIT
- 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.14 npm1MIT