Documentation

Canvas LMS MCP Docs

> Source of truth: /Users/gabrielemuratori/canvas-mcp-project (Next.js 16 marketing/docs site, host-routed: blog./blog, admin./admin). > Product: canvaslmsmcp — an MCP server that exposes Canvas LMS as agent tools. npm package: `canvaslmsmcpkit`. Surface: 27 role-scoped tools. Transport: stdio, launched with npx -y canvaslmsmcpkit. > Not affiliated with Instructure.

Everything below is the finished, copy-paste-ready reference content. It is organized as: (1) the site information architecture, then (2) full written content for each page, then (3) the per-category tool reference intros.

1. Information Architecture (nav tree)

canvaslmsmcp docs
│
├── Getting Started
│   ├── What is canvaslmsmcp
│   ├── Prerequisites
│   ├── Get a Canvas API token
│   ├── Quickstart (one npx line)
│   └── First prompts
│
├── Configuration
│   ├── Environment variables (overview)
│   ├── CANVAS_API_TOKEN
│   ├── CANVAS_BASE_URL
│   ├── CANVAS_ROLE
│   ├── Optional / advanced flags
│   └── Config precedence & validation
│
├── Tools by Category
│   ├── Overview (the 27-tool surface)
│   ├── Courses & Enrollment
│   ├── Assignments
│   ├── Submissions
│   ├── Grades & Progress
│   ├── Modules & Files
│   ├── Discussions & Announcements
│   ├── Inbox & Messaging
│   ├── Calendar & Planner
│   └── GraphQL & Utility
│
├── Client Setup
│   ├── Claude Desktop
│   ├── Cursor
│   ├── VS Code
│   ├── Windsurf
│   ├── Codex (OpenAI)
│   └── Claude Code (CLI)
│
├── Roles
│   ├── Role model overview
│   ├── Role → tool matrix
│   └── Read vs write scoping
│
├── Security
│   ├── Token handling
│   ├── Least-privilege roles
│   ├── Network & data flow
│   └── Revocation & rotation
│
├── FAQ
│
└── Troubleshooting
    ├── 401 Unauthorized
    ├── 403 Forbidden / permission
    ├── 429 / Rate Limit Exceeded
    ├── Empty shell (server connects, no data)
    └── Diagnostics & logs

2. Page Content

Getting Started

canvaslmsmcp is a Model Context Protocol server that gives any MCP-capable AI client a Canvas LMS login. Your agent reads your entire course load — deadlines, grades, files, announcements, inbox — and can act on it (submit work, post discussion replies, drop calendar events) through 27 clean, role-scoped tools. No browser automation, no scraping. Every call is a first-class Canvas REST or GraphQL request made with your own access token.

It runs locally over stdio. There is nothing to install and no account to create: npx fetches the package on first run, the server starts, and it talks to Canvas directly from your machine.

#### Prerequisites

| Requirement | Notes | |---|---| | Node.js ≥ 18 | npx ships with Node. Check with node -v. | | A Canvas account | Any Instructure-hosted or self-hosted Canvas instance where API access is enabled. | | A Canvas API access token | See below. | | An MCP client | Claude Desktop, Cursor, VS Code, Windsurf, Codex, or Claude Code. | | Your Canvas base URL | e.g. https://school.instructure.com. |

#### Get a Canvas API token

  1. Log into Canvas in a browser.
  2. Go to Account → Settings.
  3. Scroll to Approved Integrations.
  4. Click + New Access Token.
  5. Set a Purpose (e.g. canvaslmsmcp) and an optional expiry.
  6. Click Generate Token and copy it immediately — Canvas shows the full token only once.

> The token inherits your permissions. It can do anything in Canvas that you can do, and nothing more. Treat it like a password. To narrow what the agent can do further, use CANVAS_ROLE (see Configuration and Roles).

#### Quickstart (one command)

Inspect the full tool list and print a ready-to-paste config:

npx -y canvaslmsmcpkit --help

Run the server directly (stdio) to smoke-test your credentials:

CANVAS_API_TOKEN=your-token \
CANVAS_BASE_URL=https://school.instructure.com \
CANVAS_ROLE=student \
npx -y canvaslmsmcp

In practice you don't run it by hand — you point an MCP client at it. Jump to Client Setup for exact JSON for your client.

#### First prompts

Once the server is wired into your client, try:

Configuration

canvaslmsmcp is configured entirely through environment variables passed by your MCP client (in the env block of the server config) or exported in your shell. There is no config file of its own.

#### Environment variables

| Variable | Required | Default | Example | |---|---|---|---| | CANVAS_API_TOKEN | Yes | — | 1234~AbCd... | | CANVAS_BASE_URL | Yes | — | https://school.instructure.com | | CANVAS_ROLE | No | student | student \| teacher \| ta \| observer \| admin |

Optional/advanced flags are listed at the end of this section.

#### CANVAS_API_TOKEN

The Canvas API access token generated under Account → Settings → Approved Integrations. This is the only credential the server uses; every request is authenticated with Authorization: Bearer $CANVAS_API_TOKEN.

Common mistakes

#### CANVAS_BASE_URL

The root URL of your Canvas instance, scheme included, no trailing slash, no path.

The server derives the REST base (/api/v1) and the GraphQL endpoint (/api/graphql) from this value. A mismatched region or environment is the #1 cause of a server that connects cleanly but returns no courses.

#### CANVAS_ROLE

Selects which of the 27 tools are exposed to the agent and, for a few tools, which fields are returned. This is client-side tool filtering — a guardrail, not a Canvas permission boundary.

| Value | Intended user | Exposes | |---|---|---| | student *(default)* | Learners | Read across own courses + own submissions/messages; write limited to submitting own work, posting discussion replies, sending inbox messages, creating own calendar events. | | ta | Teaching assistants | Student surface plus read of section rosters and others' submissions where the token allows. | | teacher | Instructors | TA surface plus grade/submission reads across enrolled students, announcements, broader messaging. | | observer | Parents / auditors | Read-only across observed students; no write tools. | | admin | Account/sub-account admins | Full read surface + graphql passthrough; write tools gated to what the token permits. |

If unset, the server defaults to student — the smallest useful surface. See Roles for the full tool matrix.

> Security note: CANVAS_ROLE=student on an instructor's token still cannot elevate the agent — but it *does* hide the higher-risk tools from the model, which meaningfully reduces the blast radius of a bad prompt. Always set the *lowest* role that fits the task.

#### Optional / advanced flags

These are read from the environment when present. Omit them for defaults.

| Variable | Default | Purpose | |---|---|---| | CANVAS_TIMEZONE | Canvas account TZ | IANA tz (e.g. America/New_York) used to render due dates in local time. | | CANVAS_PAGE_SIZE | 50 | per_page for paginated REST list calls (max 100). | | CANVAS_MAX_CONCURRENCY | 4 | Parallel in-flight requests for bulk tools (download_course_materials, term_snapshot). Lower it if you hit rate limits. | | CANVAS_READ_ONLY | false | If true, forcibly disables all write tools regardless of CANVAS_ROLE. | | CANVAS_LOG_LEVEL | info | silent \| error \| info \| debug. debug logs request URLs and status codes to stderr. |

#### Config precedence & validation

  1. Explicit env in the client's MCP config wins.
  2. Then the inherited shell environment.
  3. On startup the server validates CANVAS_API_TOKEN and CANVAS_BASE_URL are present and that the URL parses; it makes one GET /api/v1/users/self call to confirm auth. A failure here surfaces in the client as a server that fails to initialize — check client logs.

Client Setup

The server binary is the same everywhere: npx -y canvaslmsmcpkit over stdio, with three env vars. Only the file location and JSON schema differ per client. Replace your-token and the base URL with your values.

#### Claude Desktop

Config file:

{
  "mcpServers": {
    "canvas-lms": {
      "command": "npx",
      "args": ["-y", "canvaslmsmcpkit"],
      "env": {
        "CANVAS_API_TOKEN": "your-token",
        "CANVAS_BASE_URL": "https://school.instructure.com",
        "CANVAS_ROLE": "student"
      }
    }
  }
}

Fully quit and reopen Claude Desktop after saving. The tools appear under the connector/plug icon.

#### Cursor

Config file:

{
  "mcpServers": {
    "canvas-lms": {
      "command": "npx",
      "args": ["-y", "canvaslmsmcpkit"],
      "env": {
        "CANVAS_API_TOKEN": "your-token",
        "CANVAS_BASE_URL": "https://school.instructure.com",
        "CANVAS_ROLE": "student"
      }
    }
  }
}

Enable it under Settings → MCP and confirm the green dot / tool count.

#### VS Code

Config file: .vscode/mcp.json (workspace) or the mcp block in User Settings. VS Code uses a `servers` key and supports secret `inputs` so the token is never written to disk:

{
  "inputs": [
    {
      "type": "promptString",
      "id": "canvas-token",
      "description": "Canvas API Token",
      "password": true
    }
  ],
  "servers": {
    "canvas-lms": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "canvaslmsmcpkit"],
      "env": {
        "CANVAS_API_TOKEN": "${input:canvas-token}",
        "CANVAS_BASE_URL": "https://school.instructure.com",
        "CANVAS_ROLE": "student"
      }
    }
  }
}

Click Start on the server in the mcp.json gutter, then use it from Copilot Chat's Agent mode. VS Code prompts once for the token and stores it in the secret store.

#### Windsurf

Config file: ~/.codeium/windsurf/mcp_config.json. Windsurf uses the mcpServers schema (no type field):

{
  "mcpServers": {
    "canvas-lms": {
      "command": "npx",
      "args": ["-y", "canvaslmsmcpkit"],
      "env": {
        "CANVAS_API_TOKEN": "your-token",
        "CANVAS_BASE_URL": "https://school.instructure.com",
        "CANVAS_ROLE": "student"
      }
    }
  }
}

Open Windsurf → Settings → Cascade → MCP Servers and click Refresh.

#### Codex (OpenAI)

Config file: ~/.codex/config.toml. Codex uses TOML under [mcp_servers.<name>]:

[mcp_servers.canvas-lms]
command = "npx"
args = ["-y", "canvaslmsmcpkit"]
env = { CANVAS_API_TOKEN = "your-token", CANVAS_BASE_URL = "https://school.instructure.com", CANVAS_ROLE = "student" }

Restart Codex. Verify with codex mcp list (the server should report its tools).

#### Claude Code (CLI)

Add it with one command (project scope by default; add --scope user for global):

claude mcp add canvas-lms \
  --env CANVAS_API_TOKEN=your-token \
  --env CANVAS_BASE_URL=https://school.instructure.com \
  --env CANVAS_ROLE=student \
  -- npx -y canvaslmsmcpkit

Or commit a project-shared .mcp.json in the repo root:

{
  "mcpServers": {
    "canvas-lms": {
      "command": "npx",
      "args": ["-y", "canvaslmsmcpkit"],
      "env": {
        "CANVAS_API_TOKEN": "your-token",
        "CANVAS_BASE_URL": "https://school.instructure.com",
        "CANVAS_ROLE": "student"
      }
    }
  }
}

> For .mcp.json committed to a repo, leave the token empty and inject it from the shell environment ("CANVAS_API_TOKEN": "${CANVAS_API_TOKEN}") so you never commit a secret. Verify with claude mcp list and /mcp inside a session.

Roles

CANVAS_ROLE performs role-based tool filtering at server startup: the server only registers the tools appropriate to the role, so the model never sees — and therefore cannot call — anything outside that surface. This is defense-in-depth on top of Canvas's own permission checks (which always apply to the underlying token).

#### Role → tool matrix

| Tool | student | ta | teacher | observer | admin | |---|:--:|:--:|:--:|:--:|:--:| | list_courses | ✅ | ✅ | ✅ | ✅ | ✅ | | get_course | ✅ | ✅ | ✅ | ✅ | ✅ | | get_syllabus | ✅ | ✅ | ✅ | ✅ | ✅ | | term_snapshot ★ | ✅ | ✅ | ✅ | ✅ | ✅ | | list_assignments | ✅ | ✅ | ✅ | ✅ | ✅ | | get_assignment | ✅ | ✅ | ✅ | ✅ | ✅ | | whats_due ★ | ✅ | ✅ | ✅ | ✅ | ✅ | | submit_assignment ★ | ✅ | ✅ | ✅ | ⛔ | ✅ | | get_submission | ✅ (own) | ✅ | ✅ | ✅ | ✅ | | list_missing_submissions | ✅ | ✅ | ✅ | ✅ | ✅ | | add_submission_comment | ✅ | ✅ | ✅ | ⛔ | ✅ | | get_grades | ✅ | ✅ | ✅ | ✅ | ✅ | | pass_status ★ | ✅ | ✅ | ✅ | ✅ | ✅ | | list_modules | ✅ | ✅ | ✅ | ✅ | ✅ | | list_module_items | ✅ | ✅ | ✅ | ✅ | ✅ | | list_files | ✅ | ✅ | ✅ | ✅ | ✅ | | download_file | ✅ | ✅ | ✅ | ✅ | ✅ | | download_course_materials ★ | ✅ | ✅ | ✅ | ✅ | ✅ | | list_announcements | ✅ | ✅ | ✅ | ✅ | ✅ | | list_discussions | ✅ | ✅ | ✅ | ✅ | ✅ | | post_discussion_reply | ✅ | ✅ | ✅ | ⛔ | ✅ | | inbox | ✅ | ✅ | ✅ | ✅ | ✅ | | send_message | ✅ | ✅ | ✅ | ⛔ | ✅ | | list_calendar_events | ✅ | ✅ | ✅ | ✅ | ✅ | | create_calendar_event | ✅ | ✅ | ✅ | ⛔ | ✅ | | graphql | ⛔ | ⛔ | ✅ | ⛔ | ✅ | | whoami | ✅ | ✅ | ✅ | ✅ | ✅ |

★ = flagship tool. observer is fully read-only. graphql (raw passthrough) is restricted to teacher/admin because it can query any endpoint the token permits and bypasses the curated surface.

#### Read vs write scoping

Security

canvaslmsmcp is designed to run locally, on your own token, with no intermediary service. Nothing is sent to a canvaslmsmcp backend — the site at canvaslmsmcp.com is documentation only.

Token handling

Least-privilege roles

Network & data flow

Revocation & rotation

FAQ

Is this affiliated with Instructure / Canvas? No. It is an independent open MCP server that uses the public Canvas API.

Does my token leave my machine? Only to your Canvas instance, over HTTPS. There is no canvaslmsmcp server in the loop.

Do I need to install anything? No. npx -y canvaslmsmcpkit fetches and runs it on demand. Node ≥ 18 is the only requirement.

Why 27 tools when I only see ~20 on the homepage? The homepage shows a representative sample. The full 27-tool surface is in Tools by Category.

Can it grade / act as a teacher? With a teacher/admin token and the matching CANVAS_ROLE, the write and graphql tools unlock — bounded by what the token can actually do in Canvas.

Which base URL for the beta/test environment? Only use *.beta. or *.test. hosts deliberately; they are reset copies and will look empty/stale against production tokens.

It connected but shows no courses — bug? Almost always a wrong CANVAS_BASE_URL (region/environment) or a token from a different account. See Troubleshooting → Empty shell.

Troubleshooting

Turn on verbose logging first: set CANVAS_LOG_LEVEL=debug in the server env, restart the client, and read the client's MCP/server logs (Claude Desktop: Developer → Open logs; Cursor/Windsurf: MCP panel; VS Code: Output → MCP; Claude Code: /mcp and claude mcp list).

#### 401 Unauthorized

The token is missing, malformed, expired, or revoked.

#### 403 Forbidden / permission

Auth succeeded but the action isn't allowed.

#### 429 / "Rate Limit Exceeded"

Canvas throttles per-token using a leaky-bucket. Under load it returns 403 Forbidden with body 403 Forbidden (Rate Limit Exceeded) and/or 429, plus X-Rate-Limit-Remaining headers.

#### Empty shell (server connects, returns no data)

The most common non-error failure: the server initializes, tools list fine, but list_courses is empty.

#### Diagnostics & logs

3. Per-Category Tool Reference Intros

The 27 tools are grouped into 9 Canvas domains. Each category page opens with the intro below, followed by per-tool detail (params, returns, role scope). Star (★) tools are the flagship, agent-first composites.

Courses & Enrollment

list_courses · get_course · get_syllabus · term_snapshot ★

Your agent's entry point into Canvas. These tools resolve *what you're enrolled in* before anything else acts on it. list_courses returns active enrollments with term and role; get_course pulls a single course's metadata, syllabus body, and detects external tools (LTI) that may hide content behind a third party; get_syllabus isolates the syllabus HTML for summarization. `term_snapshot ★` is the workhorse: one GraphQL round-trip that hydrates every course, assignment, due date, and grade for a whole term — use it to prime context in a single call instead of fanning out dozens of REST requests. Every tool here is read-only and available to all roles.

Assignments

list_assignments · get_assignment · whats_due ★

The coursework surface. list_assignments enumerates a course's assignments with due dates, point values, and submission types; get_assignment drills into one — lock/unlock windows, allowed attempts, rubric, and accepted submission formats — which the agent should always read before submitting. `whats_due ★` is the cross-course deadline brain: it merges assignments, quizzes, and events from *all* active courses into one dated, de-duplicated feed with per-item submission status, so "what's due this week?" is a single tool call, not a loop. Read-only; all roles.

Submissions

submit_assignment ★ · get_submission · list_missing_submissions · add_submission_comment

Where the agent acts on your behalf. `submit_assignment ★` runs the complete Canvas upload flow — text entry, URL, or file (with the multi-step file-upload handshake) — and pre-flights the target: it checks the assignment is unlocked, the submission type is accepted, and attempts remain, refusing rather than failing silently. get_submission reports status, attempt count, score, and lateness for a given assignment; list_missing_submissions surfaces everything past-due and unsubmitted across courses; add_submission_comment posts a comment on a submission. Write tools here are hidden from observer and killed entirely by CANVAS_READ_ONLY=true.

Grades & Progress

get_grades · pass_status ★

Your standing, live. get_grades returns current and (where Canvas exposes them) projected scores per course, plus the grading scheme. `pass_status ★` goes further: it computes, per course, whether you have *already banked* a passing grade given points earned versus points still outstanding — the "can I stop worrying about this class?" answer — and flags courses that are one bad assignment away from dropping below the line. Both are read-only and available to all roles; what you can see is bounded by the token (students see only their own).

Modules & Files

list_modules · list_module_items · list_files · download_file · download_course_materials ★

Course materials, browsable and pullable. list_modules returns a course's module structure with completion state; list_module_items expands one module into its pages, files, quizzes, and links; list_files enumerates the file tree; download_file fetches a single file to your local disk. `download_course_materials ★` is the bulk archiver: it walks every module and file in a course (or across courses) and pulls lecture decks, PDFs, and resources for offline study in one parallelized run — tune CANVAS_MAX_CONCURRENCY to stay under rate limits. All roles; the download tools write to your local filesystem, so scope the target directory.

Discussions & Announcements

list_announcements · list_discussions · post_discussion_reply

Course communication you can't afford to miss. list_announcements returns recent announcements per course, newest first — the channel where moved exams and deadline changes actually land. list_discussions lists discussion topics with reply counts and your participation state. post_discussion_reply posts a reply to a topic (the participation-points tool). The reply tool is a write action: hidden from observer, disabled by CANVAS_READ_ONLY=true.

Inbox & Messaging

inbox · send_message

Canvas's private conversations. inbox is a non-mutating read of your conversation threads (subjects, participants, latest message) so an agent can triage without side effects. send_message composes and sends a Canvas inbox message to a user or course context. send_message is a write tool — excluded for observer and under CANVAS_READ_ONLY. Message *content* is always bounded by who your token is allowed to contact.

Calendar & Planner

list_calendar_events · create_calendar_event

Time management. list_calendar_events reads calendar events and planner items across your courses within a date window, rendered in CANVAS_TIMEZONE. create_calendar_event drops a new event onto your Canvas calendar — pair it with whats_due to materialize a study schedule from open deadlines. Creating events is a write action (not available to observer, off under read-only mode).

GraphQL & Utility

graphql · whoami

The escape hatch and the health check. `graphql` is a raw passthrough to Canvas's GraphQL endpoint — hand it any query to fetch exactly the fields you need in one request, beyond the curated tools. Because it can reach anything the token permits, it is restricted to `teacher` and `admin` roles. whoami returns the authenticated user's identity and is the cheapest end-to-end diagnostic: a single call that proves your token, base URL, and role are wired correctly. Available to every role.

*End of reference. The nav tree in §1 maps 1:1 to the page content in §2 and the category intros in §3; wire each nav leaf to the matching section.*