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 & logs2. 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
- Log into Canvas in a browser.
- Go to Account → Settings.
- Scroll to Approved Integrations.
- Click + New Access Token.
- Set a Purpose (e.g.
canvaslmsmcp) and an optional expiry. - 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:
- "What's due this week across all my courses?"
- "Have I banked a passing grade in every class?"
- "Download every file from my Organic Chemistry modules."
- "Submit
paper.pdfto Assignment 3 in History 210." - "Any announcements about a moved exam?"
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.
- Format: typically
<user-shard>~<secret>(e.g.7~a1b2c3...). Copy it verbatim, including the~. - Scope: the token acts as you.
CANVAS_ROLEonly narrows the *tool surface*; it does not change what the underlying token is permitted to do at the Canvas level. - Never hardcode this into a file you commit. Use your client's secret input where available (see VS Code), or keep configs out of version control.
- Expiry: if you set an expiry when creating the token, the server will start returning
401after that date. Generate a new one and update the env.
Common mistakes
- Pasting a trailing space or newline (breaks the
Bearerheader →401). - Copying a *refresh* token or OAuth client secret instead of a personal access token.
- Using a token from a different Canvas account than
CANVAS_BASE_URLpoints at (→ empty shell).
#### CANVAS_BASE_URL
The root URL of your Canvas instance, scheme included, no trailing slash, no path.
- Correct:
https://school.instructure.com - Correct (self-hosted):
https://canvas.university.edu - Wrong:
school.instructure.com(missing scheme) - Wrong:
https://school.instructure.com/(trailing slash) - Wrong:
https://school.instructure.com/courses(path included) - Wrong:
https://school.beta.instructure.comunless you *intend* the beta environment — beta is a periodically-reset copy and will look like an empty or stale shell against your production token.
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
- Explicit
envin the client's MCP config wins. - Then the inherited shell environment.
- On startup the server validates
CANVAS_API_TOKENandCANVAS_BASE_URLare present and that the URL parses; it makes oneGET /api/v1/users/selfcall 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:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"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:
- Global:
~/.cursor/mcp.json - Per-project:
.cursor/mcp.jsonin 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"
}
}
}
}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
- Read tools are exposed to every role (subject to the matrix). What they *return* is still bounded by the token — a student's token simply cannot read another student's submission even via
get_submission. - Write tools (
submit_assignment,add_submission_comment,post_discussion_reply,send_message,create_calendar_event) are the ones that mutate Canvas. They are hidden forobserver, and can be globally disabled for *any* role withCANVAS_READ_ONLY=true. - Setting a role above your token's real permissions does not grant access — the tool will appear but its calls return
403. Setting a role below is the recommended safe default.
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
- The token lives only in your MCP client's config
env(or your shell). It is sent to Canvas over TLS as aBearerheader and never logged atinfolevel.CANVAS_LOG_LEVEL=debuglogs request URLs but redacts theAuthorizationheader. - Prefer client secret stores where available (VS Code
inputs, OS keychains) over plaintext JSON. - Never commit a populated config. For shared
.mcp.json/.cursor/mcp.json, use${CANVAS_API_TOKEN}interpolation and keep the real value in your environment or a git-ignored.env.
Least-privilege roles
- Default to
CANVAS_ROLE=student. Escalate only for the specific task. - Use
CANVAS_READ_ONLY=truefor any read-only workflow (research, deadline monitoring, bulk downloads) — it removes every mutating tool from the model's reach. - Create a dedicated, expiring Canvas token for the agent rather than reusing a long-lived personal one.
Network & data flow
- Data path: your machine → `CANVAS_BASE_URL` over HTTPS → back to your machine. No third-party hop.
download_file/download_course_materialswrite to your local filesystem; scope the target directory and review what an agent pulls before running bulk jobs.- The
graphqltool is a raw passthrough. It is role-gated toteacher/adminprecisely because it can reach any node the token allows.
Revocation & rotation
- Revoke instantly in Account → Settings → Approved Integrations → (trash icon). Revocation is immediate; the server's next call returns
401. - Rotate on a schedule and after any suspected exposure. Set token expiries so a leaked token dies on its own.
- If a token is compromised, revoke first, then rotate; there is no server-side session to invalidate.
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.
- Confirm
CANVAS_API_TOKENis set and has no leading/trailing whitespace or newline. - Regenerate the token (Account → Settings → New Access Token) if it expired or was revoked.
- Verify you copied a personal access token, not an OAuth client secret or refresh token.
- Smoke-test:
curl -H "Authorization: Bearer $CANVAS_API_TOKEN" $CANVAS_BASE_URL/api/v1/users/selfshould return your user JSON.
#### 403 Forbidden / permission
Auth succeeded but the action isn't allowed.
- Wrong role for the token: you set
CANVAS_ROLE=adminon a student token. The tool shows but Canvas rejects the call. Set the role your token actually holds. - Token lacks scope: if your Canvas admin issued a scoped developer key, it may not cover the endpoint. Use an unscoped personal token or ask for the scope.
- Institution disabled the API for that resource. Confirm with your Canvas admin.
#### 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.
- Lower
CANVAS_MAX_CONCURRENCY(e.g.2) for bulk tools. - Reduce
CANVAS_PAGE_SIZEand avoid runningterm_snapshot/download_course_materialsback-to-back. - The server backs off and retries automatically; persistent throttling means too many parallel agent calls — space them out.
#### Empty shell (server connects, returns no data)
The most common non-error failure: the server initializes, tools list fine, but list_courses is empty.
- Wrong `CANVAS_BASE_URL` region/environment — e.g. pointing at
*.beta.instructure.comor the wrong subdomain. Fix to your production host, no trailing slash, no path. - Token from a different account than the base URL serves.
- No active enrollments in the current term — try
list_courseswith past/future terms, or confirm you have live courses in the Canvas web UI. - Role too narrow for what you're asking (an
observersees only observed students). - Confirm identity with the
whoamitool — if it returns the wrong person or nothing, your token/base-URL pair is mismatched.
#### Diagnostics & logs
whoami— cheapest end-to-end check (auth + base URL + identity in one call).CANVAS_LOG_LEVEL=debug— prints each request URL + status to stderr (token redacted).npx -y canvaslmsmcpkit --help— reprints the tool list and a known-good config block.- If the server won't start at all, the client shows an init failure — it's almost always a missing required env var (
CANVAS_API_TOKENorCANVAS_BASE_URL).
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.*