Skip to main content
Glama

canvas-student-mcp

The Canvas LMS MCP server that works even when your school disables API tokens.

CI License: MIT Node >= 18 TypeScript

Gives Claude (or any MCP client) live, read-only access to your Canvas account: courses, syllabus, assignments with submission status, grades, announcements, modules, pages, files, discussions, quizzes, to-dos, and calendar. Pair it with a Notion connector and archive an entire course with one prompt.

Why another Canvas MCP?

Several good Canvas MCP servers already exist — vishalsachdev/canvas-mcp, DMontgomery40/mcp-canvas-lms, mtgibbs/canvas-lms-mcp, and others. All of them require a personal API token.

Here's the problem: many universities disable self-service token generation for students. Open Account → Settings and there's simply no + New Access Token button. At those schools, every token-based server is a dead end.

This server solves that with session-cookie authentication: log into Canvas in your browser, copy the session cookie once, and you're connected. The Canvas web UI talks to the same /api/v1 REST API with that cookie, so no admin policy can block it without breaking Canvas itself.

What that requires under the hood (and what the token-based servers don't do):

  • XSSI guard stripping — cookie-authenticated Canvas responses are prefixed with while(1);, which breaks naive JSON parsing

  • Login-redirect detection — expired sessions redirect to the login page instead of returning 401; the server catches redirects and non-JSON bodies and tells you exactly how to refresh, instead of failing cryptically

  • Credentialed file downloads — token sessions get a verifier= param that makes file URLs self-authenticating; cookie sessions don't, so downloads must carry the session cookie (Canvas answers 500 otherwise). Redirects are followed manually so credentials are never forwarded to a CDN

  • Expiry-aware errors — every failure mode explains the fix in the error message itself

Design principles that differentiate it beyond auth:

  • Read-only by design. Every tool is a GET. The server physically cannot submit assignments, post discussions, or modify anything — safe to hand to an autonomous agent.

  • Context-efficient responses. Canvas API payloads are enormous; every tool trims to the fields an LLM actually needs, converts HTML to clean text (preserving link URLs), and caps pagination with explicit truncation notices.

  • Small and auditable. Strict TypeScript, three runtime dependencies (the MCP SDK, zod, and unpdf for PDF text). You can read the whole thing before trusting it with your school account.

Token auth is still supported if your school allows it — the cookie is the fallback, not the only path.

Related MCP server: canvas-parent-mcp

Tools (29)

Tool

What it does

canvas_get_profile

Verify credentials / who am I

canvas_list_courses

Courses with current grade (active / completed / all)

canvas_get_course

Course details + full syllabus as text

canvas_list_assignments

Assignments by due date w/ your submission status; bucket filters (upcoming, overdue, …)

canvas_get_assignment

Full description, rubric, your submission + score

canvas_get_grades

All-course grade overview, or per-assignment breakdown for one course

canvas_list_announcements

Announcements across active courses, or one course / date range

canvas_list_modules

Course content outline with items

canvas_list_pages / canvas_get_page

Course wiki pages, full text

canvas_list_files / canvas_get_file_link

Course files + temporary download URLs

canvas_list_discussions / canvas_get_discussion

Discussion topics and full threads

canvas_list_quizzes

Quizzes with due dates, time limits, attempts

canvas_list_todo / canvas_list_upcoming

Your to-do list and upcoming deadlines

canvas_list_calendar_events

Events or assignment deadlines in a date range

canvas_list_inbox / canvas_get_conversation

Read Canvas inbox threads — without marking them read

canvas_get_feedback

Grader comments and rubric assessments on your submissions

canvas_grade_breakdown

Grade by assignment group + what-if calculator: "what do I need on the final for an A?"

canvas_list_planner

Planner feed with new-activity flags and submission state

canvas_read_file

Extract text from course files — PDF, Word, PowerPoint, Excel, HTML, plain text

canvas_read_syllabus

Syllabus as text, whether it's typed into Canvas or posted as an attached PDF/Word file

canvas_list_groups

Your group memberships

canvas_get_module_progress

Module completion state and what each item still requires

canvas_list_peer_reviews

Peer reviews assigned to you

canvas_export_course

One-shot markdown export of an entire course — built for Notion archiving

canvas_auth_status

Diagnose the connection: which credential, stored where, still valid?

Three of these are worth calling out.

canvas_read_file turns course materials into readable text, which is what makes "quiz me on this week's slides" or "what's the late-work policy" actually work. PDFs go through unpdf; Office formats are handled in-repo — .docx, .pptx, and .xlsx are ZIP containers of XML, so a small ZIP reader over Node's built-in zlib covers all three with no dependency. canvas_read_syllabus builds on it: it detects when a syllabus is only a file link and reads the attachment instead, which is the common case (2 of the 3 courses tested). canvas_grade_breakdown implements both of Canvas's grading models (weighted-by-group and total-points), cross-checks its arithmetic against the score Canvas itself reports, and tells you when drop rules or unposted assignment groups make a projection unreliable — instead of quietly returning a confident wrong number. canvas_get_conversation passes auto_mark_as_read=false, so an agent reading your inbox doesn't silently mark your messages read; that behavior is verified against a live unread thread, not just assumed.

See ROADMAP.md for what's planned next and why writes are deliberately out of scope.

Quick start

No install needed — npx fetches it on demand:

npx canvas-student-mcp

Or from source:

git clone https://github.com/xmike04/canvas-student-mcp.git
cd canvas-student-mcp
npm install && npm run build

Get credentials

Option A — API token (if your school allows it): Canvas → Account → Settings → Approved Integrations → + New Access Token.

Option B — session cookie (for locked-down schools):

  1. Log into your school's Canvas in any browser

  2. DevTools (Cmd/Ctrl+Shift+I) → Network tab → refresh

  3. Click any request to your Canvas domain → Request Headers → copy the full cookie: value (or just the canvas_session=... pair — that one cookie is sufficient)

Either credential grants read access to your Canvas account. Treat it like a password.

Store the credential (macOS: use the Keychain)

MCP client configs are plaintext JSON. On macOS you can keep the credential out of them entirely:

security add-generic-password -s canvas-student-mcp -a cookie -w 'canvas_session=PASTE_VALUE_HERE' -U

Use -a token instead of -a cookie for an API token. The server checks environment variables first, then the Keychain, so this is opt-in and nothing breaks if you skip it. CANVAS_NO_KEYCHAIN=1 disables the lookup.

Register with Claude

Claude Code — with the credential in the Keychain, the config holds no secret at all:

claude mcp add canvas --scope user \
  --env CANVAS_BASE_URL=https://yourschool.instructure.com \
  -- npx -y canvas-student-mcp

Passing the credential inline instead of using the Keychain:

claude mcp add canvas --scope user \
  --env 'CANVAS_COOKIE=canvas_session=PASTE_VALUE_HERE' \
  --env CANVAS_BASE_URL=https://yourschool.instructure.com \
  -- npx -y canvas-student-mcp

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "canvas": {
      "command": "node",
      "args": ["/absolute/path/to/canvas-student-mcp/dist/index.js"],
      "env": {
        "CANVAS_COOKIE": "canvas_session=PASTE_VALUE_HERE",
        "CANVAS_BASE_URL": "https://yourschool.instructure.com"
      }
    }
  }
}

Use CANVAS_API_TOKEN instead of CANVAS_COOKIE for token auth (token wins if both are set). Verify with: "check my Canvas profile."

When the cookie expires (your browser session ends), every tool tells you plainly — re-copy and update the config. With "stay signed in" checked, sessions typically last weeks.

Agent skills

Three packaged workflows ship in skills/. Copy any of them into ~/.claude/skills/ (or your project's .claude/skills/) and Claude will use them automatically when the request fits:

Skill

What it does

canvas-morning-check

Daily briefing: what's due, new announcements, unread messages, new grades

canvas-week-plan

Reads the actual assignments and builds a day-by-day plan for the week

canvas-grade-check

Grade standing plus what-if answers, with the caveats carried through

cp -R skills/canvas-morning-check ~/.claude/skills/

Things to ask once connected

  • "What's due in the next two weeks across all my classes?"

  • "What's my current grade in each course, and which assignments am I missing?"

  • "Summarize this week's announcements from all my courses."

  • "Export my BIOL 1710 course and archive it into my Notion School folder." (with a Notion connector)

  • "Read the Week 3 page in my history course and quiz me on it."

Architecture notes

  • stdio transport, stateless — one process per client session, no ports, no telemetry, no storage. Data flows Canvas → this process → your MCP client, nowhere else.

  • Auto-pagination follows Canvas Link: rel="next" headers, capped at 5 pages × 100 items with explicit truncation notices so agent context stays bounded.

  • HTML → text conversion for syllabi, descriptions, announcements, and pages — structural tags become line breaks/bullets, links become text (url).

  • Zod input schemas on every tool; MCP annotations (readOnlyHint) declared throughout.

Development

npm run build   # strict TypeScript compile
npm test        # smoke test: MCP handshake, all 30 tools register, error paths

The smoke test runs entirely offline — CI needs no Canvas account, and it sets CANVAS_NO_KEYCHAIN=1 so a real stored credential can't leak into a test run.

Releasing

Publishing runs from CI (.github/workflows/release.yml), so no one publishes from a laptop:

npm version minor && git push --follow-tags

Pushing the tag triggers a build, the full test suite, a package-contents inspection, and a guard that the tag matches package.json — then publishes with provenance, which cryptographically links the published tarball to the commit and workflow that built it. Running the workflow manually from the Actions tab does everything except publish, as a dry run.

Security model

  • Read-only: every Canvas call is a GET; no tool can write to Canvas. Even reading your inbox leaves messages unread.

  • Credentials live in your MCP client's env config or the macOS Keychain — never on disk in this repo, never transmitted anywhere but your school's Canvas domain. File downloads follow redirects manually so credentials are never forwarded to a CDN.

  • Rotate at will: log out of Canvas (or revoke the token) and the credential is dead everywhere.

  • canvas_auth_status tells you which credential is in use, where it's stored, and whether it still works.

License

MIT

Available Tools

30 tools
canvas_auth_statusCheck credential statusA
Read-only

Diagnose the Canvas connection: which credential is in use, where it's stored, and whether it still works. Run this first when something fails, or before a scheduled job, to distinguish an expired session from a real error.

Inputs: no named parameters.

canvas_export_courseExport course to markdownA
Read-only

One-shot export of a course as a single markdown document: details, syllabus, grade, all assignments with submission status, module outline, and recent announcements. Designed for archiving to Notion or notes apps.

Inputs: course_id (required).

canvas_get_assignmentGet assignment detailsA
Read-only

Get one assignment's full details: description (as text), due/lock dates, rubric, and the user's submission with score and grade.

Inputs: course_id (required), assignment_id (required).

canvas_get_conversationRead a conversation threadA
Read-only

Read the full message thread of one conversation, including every reply. Does NOT mark the conversation as read.

Inputs: conversation_id (required).

canvas_get_courseGet course details + syllabusA
Read-only

Get one course's details including the full syllabus text, term, and current score. course_id comes from canvas_list_courses.

Inputs: course_id (required).

canvas_get_discussionRead a discussion threadA
Read-only

Read a discussion topic's full thread, including replies.

Inputs: topic_id (required), course_id (required).

canvas_get_feedbackGet grader feedbackA
Read-only

Get grader comments and rubric assessments on your submissions — what the instructor or TA actually wrote. Omit course_id to check every active course. Only returns submissions that have feedback or a grade.

Inputs: course_id, include_empty.

canvas_get_gradesGet gradesA
Read-only

Without course_id: current score/grade for every active course. With course_id: every graded submission in that course (assignment name, score, points possible, late/missing flags) — useful for 'what's my grade breakdown'.

Inputs: course_id.

canvas_get_module_progressModule completion progressA
Read-only

Show module-by-module progress: which modules are locked, started, or completed, and for each item what Canvas requires to mark it done (view it, submit it, contribute, or score a minimum) and whether you've done it.

Inputs: course_id (required), incomplete_only.

canvas_get_pageRead a course pageA
Read-only

Read one course page's full content as text. page_url is the 'url' slug from canvas_list_pages or canvas_list_modules.

Inputs: page_url (required), course_id (required).

canvas_get_profileGet my Canvas profileA
Read-only

Fetch the authenticated user's Canvas profile (name, primary email, id). Use this to verify the API token works.

Inputs: no named parameters.

canvas_grade_breakdownGrade breakdown & what-if calculatorA
Read-only

Break a course grade down by assignment group (with weights), showing what's graded, what's left, and your current standing. Pass target_grade (e.g. 90) to compute the average you need on all remaining work to finish at that grade.

Inputs: course_id (required), target_grade.

canvas_list_announcementsList announcementsA
Read-only

List announcements. Defaults to all active courses over the last 30 days; pass course_id and/or start_date (ISO) to narrow or widen.

Inputs: end_date, course_id, start_date.

canvas_list_assignmentsList assignmentsA
Read-only

List a course's assignments ordered by due date, each with the user's submission status (submitted/score/late/missing). Optional bucket filters: upcoming, past, overdue, undated, ungraded, unsubmitted, future.

Inputs: course_id (required), bucket.

canvas_list_calendar_eventsCalendar eventsA
Read-only

Calendar events (lectures, office hours, deadlines) between two dates. type='assignment' shows assignment due dates instead of plain events.

Inputs: end_date (required), start_date (required), type, course_id.

canvas_list_coursesList my coursesA
Read-only

List the user's Canvas courses with current score/grade per course. state='active' (default) for this semester, 'completed' for past courses, 'all' for everything.

Inputs: state.

canvas_list_discussionsList discussionsA
Read-only

List a course's discussion topics with unread counts and due dates.

Inputs: course_id (required).

canvas_list_filesList course filesA
Read-only

List files in a course (slides, PDFs, handouts). Use search_term to filter by name. Returns file IDs for canvas_get_file_link.

Inputs: course_id (required), search_term.

canvas_list_groupsList my groupsA
Read-only

List the Canvas groups you belong to (project teams, study groups, sections) with member counts and their course.

Inputs: no named parameters.

canvas_list_inboxList Canvas inbox messagesA
Read-only

List conversations from the Canvas inbox (messages from instructors, TAs, and classmates) with sender, course, preview, and read state. Use scope='unread' for just unread messages.

Inputs: limit, scope.

canvas_list_modulesList modulesA
Read-only

List a course's modules with their items (pages, files, assignments, quizzes, links) in order — the course's content outline.

Inputs: course_id (required).

canvas_list_pagesList course pagesB
Read-only

List a course's wiki pages. Use search_term to filter by title.

Inputs: course_id (required), search_term.

canvas_list_peer_reviewsList peer reviews assigned to meA
Read-only

Find peer reviews you've been asked to complete, and their status. Scans the course's peer-review assignments; pass assignment_id to check just one.

Inputs: course_id (required), assignment_id.

canvas_list_plannerPlanner feedA
Read-only

Canvas planner feed across all courses — assignments, quizzes, discussions, announcements, and calendar events in date order, each flagged with whether it has new activity and your submission state. Richer than canvas_list_todo.

Inputs: days_back, days_ahead, new_activity_only.

canvas_list_quizzesList quizzesA
Read-only

List a course's quizzes with due dates, time limits, allowed attempts, and points.

Inputs: course_id (required).

canvas_list_todoMy to-do listA
Read-only

The user's Canvas to-do list: assignments and quizzes needing submission, across all courses.

Inputs: no named parameters.

canvas_list_upcomingUpcoming eventsA
Read-only

The user's upcoming Canvas events and assignment due dates across all courses (next ~2 weeks).

Inputs: no named parameters.

canvas_read_fileRead a course file's textA
Read-only

Download a Canvas file and extract its text — PDF, Word (.docx), PowerPoint (.pptx), Excel (.xlsx), HTML, and plain-text formats. Use this to read syllabi, lecture slides, and handouts. file_id comes from canvas_list_files or a module item's content_id.

Inputs: file_id (required), max_chars.

canvas_read_syllabusRead a course syllabus (inline or attached file)A
Read-only

Get a course's syllabus as text. Handles both cases automatically: syllabus typed into Canvas, or posted as an attached PDF/Word file (common) — in which case the file is downloaded and its text extracted.

Inputs: course_id (required), max_chars.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 30 tools

    Disambiguation4/5

    Tools are generally distinct in purpose, but there is some overlap between canvas_list_todo, canvas_list_upcoming, canvas_list_planner, and canvas_list_calendar_events. Although their descriptions help differentiate them, an agent might still select the wrong one for scheduling or task queries.

    Naming Consistency5/5

    All tool names consistently follow the 'canvas_verb_noun' pattern (e.g., canvas_list_courses, canvas_get_assignment, canvas_read_file). The naming is predictable and makes it easy for an agent to infer expected behavior.

    Tool Count4/5

    With 30 tools, the set covers a wide range of Canvas operations. While the count is on the higher side, each tool serves a specific need for a student, and the count is reasonable given the breadth of the Canvas LMS API surface.

    Completeness5/5

    The toolset provides comprehensive coverage for a student's typical needs: viewing courses, assignments, grades, modules, files, discussions, quizzes, calendar, inbox, and feedback. It includes both listing and detailed retrieval, and even covers file content reading and course export. There are no obvious gaps for a student-facing use case.

    Maintenance

    ActivityNo data
    ResponsivenessSyncing

    Related MCP Connectors

    Related MCP Servers