Skip to main content
Glama
canvas-scholar-mcp

canvas-scholar-mcp

by Ait0u5hi

Canvas Scholar MCP

CI License: MIT Node

A student-focused Model Context Protocol server for Canvas LMS. Ask your AI assistant what's due, how you're doing, and what you've missed — it reads your Canvas directly.

  • Mostly read-only. Almost every tool only reads; four tools (canvas_create_calendar_event/canvas_update_calendar_event for your calendar, canvas_create_planner_note/canvas_update_planner_note for your to-do list) write to Canvas and require confirmation before running. Nothing else is ever written back to Canvas.

  • Student-scoped. It can only see your data (/users/self/…). It cannot read a classmate's grades — enforced and regression-tested.

  • Local & private. Runs on your machine over stdio. Your token stays in your OS keychain (via the one-click installer) or a local env var. No data leaves your machine except calls to your own school's Canvas.

Requirements

  • Node.js ≥ 20 (only for the npx/from-source paths; the one-click .mcpb bundles its own runtime)

  • A Canvas API token and your school's Canvas domain (see below)

Related MCP server: Canvas LMS MCP Server

Example prompts

Once installed, just talk to your assistant:

  • "What's due this week across all my courses?"

  • "Plan my week." / "What's on my to-do list?"

  • "How are my grades — am I on track?"

  • "What did my professor say on Assign-1?"

  • "Catch me up on the discussion board in ISM 6251."

  • "What's left in the module for my stats class?"

What it can do

Tools across your whole student surface (all read-only except the four marked WRITE):

Area

Tools

Courses & assignments

list courses, list/get assignments, submission feedback (comments + rubric), peer reviews (just mine)

Grades

grades (all courses), per-course grade, weighted grade breakdown by group, late policy

What's due

missing submissions, planner items, to-do list, calendar events, web conferences (live class sessions); create/update a to-do item (WRITE, confirmation required)

Calendar

list/get calendar events; create/update a calendar event (WRITE, confirmation required)

Discussions & news

list discussions, read a full thread, group-scoped discussions (list + read a thread), announcements

Inbox

list conversations, read a thread (never marks it read), unread count

Groups

my groups, group details, group members

Files & content

course files, get a file (small text files include their content), folders, pages, syllabus, modules

Rubrics & quizzes

course rubrics, get a rubric, classic quizzes, New Quizzes, my quiz submission

Study & grades info

smart search (semantic course search, beta), grade-cutoff scheme

You & meta

my profile, class roster (degrades if hidden), API usage counter

Skills (workflow shortcuts)

The repo ships skills/ — Agent Skills that chain these tools into one-shot workflows: week-plan, student-todo, am-i-on-track, discussion-catchup, module-progress, and lecture-transcribe. Copy a skill's folder into your client's skills directory to enable it.

Lecture transcription (companion script)

When a class has a recorded web conference (BigBlueButton), canvas_list_conferences gives you its playback URL. The companion script turns that into a text transcript you can study from or feed to an LLM — kept separate from the read-only server because it does heavy media work:

node scripts/transcribe-lecture.mjs "<recording playback URL>" --out lecture.txt

Requires ffmpeg and a whisper CLI (whisper.cpp whisper-cli/main with WHISPER_MODEL, or OpenAI whisper; override with WHISPER_CMD). If it can't auto-locate the media, pass it directly with --media-url. The canvas-lecture-transcribe skill orchestrates finding the recording and running this.

Recordings include your instructor's and classmates' voices. Transcribe for your own study; don't redistribute transcripts or feed others' contributions into shared/training corpora.

Get a Canvas API token

  1. In Canvas, go to Account → Settings.

  2. Under Approved Integrations, click + New Access Token.

  3. Give it a purpose (e.g. "Canvas Scholar MCP") and — recommended — an expiration date.

  4. Copy the token. Treat it like a password; it grants access to your account.

Your Canvas domain is the host in your Canvas URL, e.g. school.instructure.com.

Install

Download canvas-scholar-mcp.mcpb from the latest release and double-click it. Claude Desktop will prompt for your token (stored in your OS keychain) and domain. No JSON, no Node install.

Claude Desktop / Cursor / any MCP client — via npx

Available once published to npm. Until then, use the from source option below.

Add to your client's MCP config:

{
  "mcpServers": {
    "canvas-scholar": {
      "command": "npx",
      "args": ["-y", "canvas-scholar-mcp"],
      "env": {
        "CANVAS_API_TOKEN": "your-token-here",
        "CANVAS_DOMAIN": "school.instructure.com"
      }
    }
  }
}

On Windows, if npx isn't found, use the full path to npx.cmd or install globally with npm i -g canvas-scholar-mcp and use "command": "canvas-scholar-mcp".

From source

git clone https://github.com/Ait0u5hi/canvas-scholar-mcp
cd canvas-scholar-mcp
npm ci && npm run build
# point your client at:  node /absolute/path/to/build/index.js

Remote / LAN (HTTP) mode

By default the server runs over stdio — each client spawns its own copy locally. If you'd rather run one always-on instance and point several MCP clients on your network at it, set MCP_TRANSPORT=http:

export MCP_TRANSPORT=http
export MCP_HTTP_HOST=0.0.0.0            # 0.0.0.0 = reachable on your LAN; 127.0.0.1 = local only (default)
export MCP_HTTP_PORT=7356               # default 7356
export MCP_AUTH_TOKEN="$(openssl rand -hex 32)"   # clients must present this as a Bearer token
export CANVAS_API_TOKEN=...             # your Canvas token (as usual)
export CANVAS_DOMAIN=school.instructure.com
npm run start:http                      # = MCP_TRANSPORT=http node build/index.js
# -> canvas-scholar-mcp: HTTP transport listening on http://0.0.0.0:7356/mcp

Point a client at it (note MCP_AUTH_TOKEN is the server-access token — it is not your Canvas token):

# Claude Code
claude mcp add --transport http canvas http://<host>:7356/mcp \
  --header "Authorization: Bearer <MCP_AUTH_TOKEN>"
// Claude Desktop has no first-class custom-header remote server, so bridge it:
{
  "mcpServers": {
    "canvas": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://<host>:7356/mcp",
               "--header", "Authorization: Bearer <MCP_AUTH_TOKEN>"]
    }
  }
}

⚠️ This widens the threat model. Over stdio the server only talks to the local client that launched it. Over HTTP it is a network service that can read your Canvas data, so:

  • Always set MCP_AUTH_TOKEN (the server refuses to start in HTTP mode without one). Requests without a valid Authorization: Bearer get 401.

  • This is API-key auth, not the full MCP OAuth 2.1 flow — a deliberate, proportionate choice for a single-user LAN box. Do not expose it to the open internet as-is.

  • Prefer TLS. The transport is plain HTTP; on anything but a trusted LAN, put it behind a reverse proxy that terminates TLS (e.g. Caddy) and use https:// URLs.

  • Bind to 127.0.0.1 unless you actually want LAN reach.

Deploying an always-on instance (systemd)

If you're running the HTTP-transport server as a long-lived service (systemd, a container, whatever), scripts/deploy.sh/scripts/rollback.sh handle pull-build-restart-verify without any host-specific assumptions baked in — they take the git ref and service name as env vars, not hardcoded values:

# On the host the server actually runs on, from the repo's working directory.
# If the systemd unit runs as a dedicated user (e.g. `User=canvas`) but you
# need root to restart it, set DEPLOY_RUN_AS so git/npm build as the right
# user while systemctl still runs as the invoker (root):
DEPLOY_REF=main DEPLOY_SERVICE=canvas-scholar-mcp DEPLOY_RUN_AS=canvas scripts/deploy.sh

# Something went wrong? Roll back to what was running before that deploy:
DEPLOY_SERVICE=canvas-scholar-mcp DEPLOY_RUN_AS=canvas scripts/rollback.sh

deploy.sh records the pre-deploy commit itself (.last-deployed-sha, gitignored) so rollback.sh doesn't need any separate state tracking. It also proactively widens the git remote's fetch refspec every run — a repo cloned with --single-branch (or any other narrowed-refspec setup) will otherwise silently fail to git fetch any ref but the one it started on, which is a real, easy-to-hit trap for a long-lived deploy checkout.

Registry sync is an optional hook, not a built-in integration. If you register this server in an MCP registry/gateway (MLflow's MCP Server Registry, the official registry.modelcontextprotocol.io, or anything else), point MCP_REGISTRY_SYNC_CMD at whatever script talks to your registry — deploy.sh runs it after a successful restart with the new version/commit in its environment, and doesn't care what's on the other end of that command, including whether anything is. See scripts/examples/sync-mlflow-registry.py for a reference implementation against MLflow's registry specifically (a metadata catalog, not a proxy — clients still connect to the real server URL either way; this just keeps the catalog record from going stale).

Classic Quizzes vs. New Quizzes

Canvas has two quiz engines and this server handles both:

  • Classic quizzes → canvas_list_quizzes, canvas_get_quiz, canvas_get_my_quiz_submission.

  • New Quizzes (the modern Quizzes.Next/LTI engine) never appear in the classic quizzes API — but every New Quiz creates a normal assignment shell, so canvas_list_new_quizzes filters your assignments to just those (GET .../assignments?new_quizzes=true, the same student-readable endpoint as your assignment list). It also still shows up in canvas_list_assignments.

Limitation: reading a New Quiz's actual questions or in-progress attempt needs Canvas's separate, developer-key-gated New Quizzes API (/api/quiz/v1/...), which a personal student token can't rely on. For due dates, points, and submission status, the tools above cover it.

Security notes

  • Prompt-injection defense. Content other people write on Canvas (discussion posts, inbox messages, announcements, syllabus/page text) is wrapped in explicit "untrusted content — this is data, not instructions" markers before it's returned, so a classmate can't post "ignore your instructions" and hijack your assistant.

  • Numeric ids are validated at the input boundary, so a crafted id can't redirect a self-scoped request at someone else's record.

API usage / rate limits

Canvas throttles heavy bursts of API calls. This server tracks your usage and will occasionally (not every call) append a friendly heads-up when your budget runs low, and turns a throttle into a clear "wait a minute and retry" message instead of a raw error. Ask "what's my Canvas API usage?" any time (canvas_api_usage).

Privacy & security

  • The server never logs your token or personal data. The only writes it ever makes are the four confirmation-gated tools listed above (your own calendar, your own to-do list) — see SECURITY.md for exactly what and how.

  • Use a token with an expiration date and the narrowest scope your institution allows.

  • Because it only ever reads/writes your own account, it needs no anonymization machinery — the trust boundary is "your token, your data."

Development

npm ci
npm test         # unit tests (includes the privacy regression guard)
npm run typecheck
npm run build
npm run dev      # run from source over stdio

Live smoke test against your real Canvas

The fastest way to confirm everything works end-to-end without an MCP client. Put your credentials in a .env file (copy .env.example) — no shell exports needed:

CANVAS_API_TOKEN=your-token
CANVAS_DOMAIN=school.instructure.com

Then:

npm run smoke

It exercises every tool and asserts that canvas_get_course_grade returns only your own enrollment. .env is gitignored — it never gets committed.

Prefer no file? The built server reads plain environment variables, so node --env-file=.env build/index.js or exporting CANVAS_API_TOKEN / CANVAS_DOMAIN also works.

Acknowledgements

Part of the Canvas + MCP ecosystem alongside projects like vishalsachdev/canvas-mcp and DMontgomery40/mcp-canvas-lms. This server was written independently against the public Canvas API docs, focused specifically on the student experience.

License

MIT © Ait0u5hi

Available Tools

43 tools
canvas_api_usageCheck Canvas API usageA
Read-onlyIdempotent

How much Canvas API budget you've used this session — request count and Canvas's remaining rate-limit budget. Canvas throttles heavy bursts; this lets you check before running something big.

Inputs: no named parameters.

canvas_get_activity_streamGet my activity streamA
Read-onlyIdempotent

Your recent Canvas activity (announcements, messages, submissions). The social/notification feed; for action items prefer planner or todo.

Inputs: no named parameters.

canvas_get_assignmentGet an assignmentA
Read-onlyIdempotent

Get one assignment (with your submission) by id.

Inputs: courseId (required), assignmentId (required).

canvas_get_assignment_groupsGet weighted grade breakdownA
Read-onlyIdempotent

Assignment groups with their weights and your submissions — shows the weighted breakdown behind a course grade. Drop rules are reported but not pre-applied.

Inputs: courseId (required).

canvas_get_calendar_eventGet a calendar eventA
Read-onlyIdempotent

Get one calendar event or assignment-date by id.

Inputs: eventId (required).

canvas_get_conversationRead an inbox threadA
Read-onlyIdempotent

Read one inbox conversation thread. Does not mark it as read (stays read-only).

Inputs: conversationId (required).

canvas_get_course_gradeGet my grade in one courseA
Read-onlyIdempotent

Your grade in a single course (only your own enrollment).

Inputs: courseId (required).

canvas_get_course_pageRead a course pageA
Read-onlyIdempotent

Get one wiki page's content (HTML stripped to text).

Inputs: pageUrl (required), courseId (required).

canvas_get_discussion_viewRead a discussion threadA
Read-onlyIdempotent

Full threaded view of a discussion topic, including reply bodies.

Inputs: topicId (required), courseId (required).

canvas_get_fileGet a fileA
Read-onlyIdempotent

File metadata by id. The returned url is a ready-to-use download link.

Inputs: fileId (required).

canvas_get_gradesGet my grades (all courses)A
Read-onlyIdempotent

Your current grade in every active course.

Inputs: no named parameters.

canvas_get_grading_standardsGet grade cutoffsA
Read-onlyIdempotent

A course's letter-grade cutoff scheme (A ≥ 93, etc.), for 'what do I need for an A?'. Returns a note if restricted to instructors.

Inputs: courseId (required).

canvas_get_groupGet a groupA
Read-onlyIdempotent

Details for one group you belong to.

Inputs: groupId (required).

canvas_get_late_policyGet a course's late policyA
Read-onlyIdempotent

A course's late-submission penalty tiers (deduction % per interval). If the course restricts this to instructors, returns a note so you can fall back to the syllabus.

Inputs: courseId (required).

canvas_get_missing_submissionsGet my missing submissionsB
Read-onlyIdempotent

Assignments you have not submitted that are due/overdue.

Inputs: courseIds.

canvas_get_my_profileGet my profileA
Read-onlyIdempotent

Your Canvas profile (name, avatar, primary email).

Inputs: no named parameters.

canvas_get_my_quiz_submissionGet my quiz submissionA
Read-onlyIdempotent

Your own attempt/submission for a classic quiz.

Inputs: quizId (required), courseId (required).

canvas_get_planner_itemsGet my planner / upcoming itemsA
Read-onlyIdempotent

Planner items (assignments, quizzes, events) in a date window. Defaults to yesterday..+14 days. Canvas's unified 'what's due/new' feed.

Inputs: endDate, startDate.

canvas_get_quizGet a classic quizA
Read-onlyIdempotent

Get one classic quiz by id.

Inputs: quizId (required), courseId (required).

canvas_get_rubricGet a rubricA
Read-onlyIdempotent

Get one rubric with its criteria and assessments.

Inputs: courseId (required), rubricId (required).

canvas_get_submission_feedbackGet my feedback on an assignmentA
Read-onlyIdempotent

Your submission for one assignment WITH the professor's comments, rubric assessment, and attempt history. Use to answer 'what did my professor say / how was I graded?'.

Inputs: courseId (required), assignmentId (required).

canvas_get_syllabusGet a course syllabusB
Read-onlyIdempotent

A course's syllabus text (HTML stripped, truncated).

Inputs: courseId (required).

canvas_get_todoGet my to-do listA
Read-onlyIdempotent

Your Canvas to-do list — items needing action right now. Overlaps with planner (dated window) and activity stream (feed); prefer this for 'what needs action'.

Inputs: no named parameters.

canvas_get_unread_message_countGet my unread message countB
Read-onlyIdempotent

How many unread inbox messages you have.

Inputs: no named parameters.

canvas_list_announcementsList course announcementsA
Read-onlyIdempotent

Recent announcements for a course.

Inputs: courseId (required).

canvas_list_assignmentsList assignments in a courseA
Read-onlyIdempotent

List assignments in a course, with your submission status and — when Canvas allows it — class score statistics (min/max/mean/quartiles) so you can see how you compare. Note: New Quizzes appear here as assignments.

Inputs: courseId (required), bucket.

canvas_list_calendar_eventsList my calendar eventsA
Read-onlyIdempotent

Calendar events and assignment dates across your courses in a date window (defaults to yesterday..+14 days). Course contexts are derived automatically. Use planner for the unified due feed; use this for raw calendar events like office hours. NOTE: live web conferences (BigBlueButton class sessions) do NOT appear here — use canvas_list_conferences for those.

Inputs: type, endDate, courseIds, startDate.

canvas_list_conferencesList my web conferencesA
Read-onlyIdempotent

Live/scheduled web conferences (BigBlueButton class sessions, etc.) with their join links — across all your courses, or one course. These are NOT in the calendar, so use this to catch live class sessions.

Inputs: state, courseId.

canvas_list_conversationsList my inboxC
Read-onlyIdempotent

List your inbox conversation threads.

Inputs: scope.

canvas_list_course_filesList course filesA
Read-onlyIdempotent

List files in a course. Locked/hidden folders are excluded automatically.

Inputs: courseId (required), searchTerm.

canvas_list_course_foldersList course foldersA
Read-onlyIdempotent

List a course's folders (for navigating the file tree).

Inputs: courseId (required).

canvas_list_course_pagesList course pagesA
Read-onlyIdempotent

List a course's wiki/content pages.

Inputs: courseId (required), searchTerm.

canvas_list_course_peopleList course classmatesA
Read-onlyIdempotent

The student roster for a course. If the course hides the roster, returns a note instead of an error.

Inputs: courseId (required).

canvas_list_course_rubricsList course rubricsB
Read-onlyIdempotent

List a course's rubrics (grading criteria).

Inputs: courseId (required).

canvas_list_coursesList my coursesA
Read-onlyIdempotent

List the courses you are enrolled in — with your current/final grade, module progress, and teaching staff in one call.

Inputs: includeConcluded.

canvas_list_discussionsList discussion topicsA
Read-onlyIdempotent

List discussion topics in a course (metadata only).

Inputs: courseId (required).

canvas_list_group_membersList group membersB
Read-onlyIdempotent

The members of a group you belong to.

Inputs: groupId (required).

canvas_list_modulesList course modulesA
Read-onlyIdempotent

List modules in a course, with their items.

Inputs: courseId (required).

canvas_list_my_groupsList my groupsA
Read-onlyIdempotent

All groups you belong to (course project groups + community).

Inputs: no named parameters.

canvas_list_new_quizzesList New QuizzesA
Read-onlyIdempotent

List a course's New Quizzes (the modern Quizzes.Next engine). These don't appear in canvas_list_quizzes; this finds them via their assignment shells. For due dates/points/status — reading a New Quiz's questions needs an instructor-gated API.

Inputs: courseId (required).

canvas_list_peer_reviewsList my peer reviewsA
Read-onlyIdempotent

Peer reviews for an assignment. By default returns only the ones assigned to YOU (you as the reviewer); pass mineOnly=false for all.

Inputs: courseId (required), assignmentId (required), mineOnly.

canvas_list_quizzesList classic quizzesA
Read-onlyIdempotent

List classic quizzes in a course. New Quizzes do NOT appear here — they surface via canvas_list_assignments.

Inputs: courseId (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 43 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action (courses, assignments, grades, feedback, calendar events, conferences, discussions, etc.). Even overlapping tools like todo, planner, and activity stream have explicit differentiators in their descriptions (e.g., 'prefer this for action needs'), leaving no ambiguity about which to call.

    Naming Consistency4/5

    The vast majority of tools follow the canvas_<verb>_<resource> pattern (get, list), with snake_case throughout. A few exceptions like canvas_smart_search and canvas_api_usage deviate from the verb_noun structure, but they remain clear and do not disrupt the overall predictable pattern.

    Tool Count2/5

    43 tools is significantly above the typical well-scoped range. While each tool maps to a specific Canvas API endpoint, the set feels heavy and could potentially be consolidated (e.g., merging multiple list/get pairs). The breadth suggests a comprehensive integration, but it exceeds the threshold where each tool clearly earns its place in a manageable set.

    Completeness5/5

    The tool set covers the full student-facing Canvas surface: grades, assignments, submissions, feedback, syllabus, calendar, files, modules, pages, quizzes (both classic and new), discussions, announcements, conversations, groups, conferences, peer reviews, search, profile, and API usage. There are no obvious gaps for a read-only student tool, and the exclusion of write operations is appropriate for the stated purpose.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers