Skip to main content
Glama

canvas-mcp

A read-only MCP server that gives Claude access to your Canvas LMS courses, so it can help you study from your teachers' actual materials: what's due, what a test covers, explanations of the slides, practice quizzes, and where you're losing points.

It can't submit, post, or change anything in Canvas. Every tool only reads.

Tools

Tool

What it's for

list_courses

Your courses, their ids, and current grades. Claude starts here.

get_upcoming

Everything due or scheduled across all classes, with submitted/missing status

list_assignments / get_assignment

Due dates, full instructions, rubric, your score, and teacher feedback

get_grades

Weighted grade breakdown (good for "what do I need on the final?")

get_syllabus

Syllabus text

list_modules

Units/weeks and their contents. Usually the best map of a course.

list_pages / get_page

Notes and pages the teacher wrote in Canvas

list_files / read_file

Reads PDF, DOCX, PPTX (with speaker notes), HTML, text/code. Long files come back in chunks.

list_announcements

Recent announcements ("test moved to Tuesday")

get_calendar

Course calendar for any date range: daily lesson topics, test days, and optionally due dates ("what did we do Tuesday?", "what's been covered since the last test?")

list_discussions / get_discussion

Discussion prompts and replies

list_quizzes

Quiz/test dates, number of questions, time limits

search_course

Finds modules, pages, files, and assignments matching a topic

Prompts (they show up as templates or slash commands in clients that support them): study_guide, quiz_me, weekly_plan.

If someone already runs a shared server for your class (Option D below), you don't need to build anything: follow What students do.


Related MCP server: Canvas LMS MCP Server

Step 1: Build it

Needs Node 20+.

cd canvas-mcp
npm install
npm run build

Step 2: Check your token

Your Canvas URL is the address you log into, for example https://yourschool.instructure.com. Leave off any /api/v1.

macOS / Linux

CANVAS_BASE_URL=https://yourschool.instructure.com CANVAS_API_TOKEN=xxxx npm run check

Windows (PowerShell)

$env:CANVAS_BASE_URL="https://yourschool.instructure.com"; $env:CANVAS_API_TOKEN="xxxx"; npm run check

If the check passes, it prints your Canvas user id and your active courses. A 401 error means the token is wrong or expired. You can make a new one under Canvas → Account → Settings → Approved Integrations → + New Access Token.

Step 3: Connect it to Claude

Pick whichever option fits how you use Claude.

Option A: Claude Code (one command)

claude mcp add canvas --scope user \
  -e CANVAS_BASE_URL=https://yourschool.instructure.com \
  -e CANVAS_API_TOKEN=xxxx \
  -e CANVAS_TZ=America/New_York \
  -- node /ABSOLUTE/PATH/TO/canvas-mcp/dist/index.js

Option B: Claude Desktop

Open the config file from Claude Desktop → Settings → Developer → Edit Config, and add this:

{
  "mcpServers": {
    "canvas": {
      "command": "node",
      "args": ["C:\\Users\\you\\canvas-mcp\\dist\\index.js"],
      "env": {
        "CANVAS_BASE_URL": "https://yourschool.instructure.com",
        "CANVAS_API_TOKEN": "xxxx",
        "CANVAS_TZ": "America/New_York"
      }
    }
  }
}

On macOS, use a path like /Users/you/canvas-mcp/dist/index.js. Restart Claude Desktop fully after saving.

Option C: Self-host it and use it from claude.ai (any device, including a Chromebook)

HTTP mode serves MCP at https://your-host/mcp/<MCP_SECRET>. claude.ai's servers connect to that URL directly, so it has to be reachable from the public internet.

  1. Generate a secret: openssl rand -hex 24

  2. Deploy the included Dockerfile (Coolify: New Resource → Dockerfile, or any Docker host). Set these env vars: CANVAS_BASE_URL, CANVAS_API_TOKEN, CANVAS_TZ, MCP_SECRET. The container listens on port 7341 and has /health for health checks.

  3. Expose it on a subdomain, for example canvas-mcp.yourdomain.com, through your reverse proxy or Cloudflare Tunnel. Don't put it behind Cloudflare Access or Basic Auth. claude.ai can't log in through those, so the secret path is the protection instead.

  4. In claude.ai, go to Settings → Connectors, add a custom connector, and paste https://canvas-mcp.yourdomain.com/mcp/<MCP_SECRET>.

Without Docker: node dist/index.js --http (it reads the same env vars). It binds to 127.0.0.1 by default, so only this machine can reach it; add --host 0.0.0.0 when a proxy on another machine needs to reach it.

⚠️ Anyone who has the full URL can read your Canvas through it. Treat the URL like a password. If it leaks, change MCP_SECRET, and also revoke the token in Canvas if you're unsure.

Option D: Host it for everyone (multi-user)

One server and one URL for a whole class or school. Each student logs in with their own Canvas address and access token. The URL holds no secret, and the server stores nothing.

What students do

  1. Open the server's page, for example https://canvas.example.com. It shows the connector URL, https://canvas.example.com/mcp, which is the same for everyone.

  2. In claude.ai, go to Settings → Connectors → Add custom connector, paste that URL, and click Connect.

  3. A login page opens. Enter your school's Canvas address and a Canvas access token (the page explains how to make one). Due dates use your browser's time zone.

  4. You land back in Claude, and the Canvas tools are ready.

To cut off access at any time, delete the token in Canvas: Account → Settings → Approved Integrations.

Deploy it on Coolify

  1. Make the key: openssl rand -hex 32. It must be random like this. A guessable key can be cracked offline from any token the server hands out, and that would expose every student's Canvas token.

  2. In Coolify: New Resource → Public Repository with this repo (or your fork), build pack Dockerfile.

  3. Set two environment variables:

    PUBLIC_URL=https://canvas.example.com
    CANVAS_MCP_KEY=<the key from step 1>

    Don't also set MCP_SECRET (the server refuses to start with both). CANVAS_BASE_URL, CANVAS_API_TOKEN and CANVAS_TZ aren't used in this mode.

  4. Set the exposed port to 7341 and the health check path to /health.

  5. Give it a public HTTPS address (below), deploy, and open PUBLIC_URL in a browser. You should see the page from step 1 above.

Without Coolify, any Docker host works the same way. Without Docker: PUBLIC_URL=… CANVAS_MCP_KEY=… node dist/index.js --http, behind a reverse proxy on the same machine.

Public HTTPS

claude.ai's servers and your students' browsers both have to reach PUBLIC_URL over HTTPS.

  • Cloudflare Tunnel: no port forwarding needed, but your domain's DNS has to be on Cloudflare. Point a public hostname straight at the container's port 7341, not at Coolify's proxy. By default, Coolify's proxy replaces every student's IP address with the tunnel's, so all students would share one login limit.

  • Coolify's built-in proxy: point the domain's DNS at your server, forward ports 80 and 443 to it, and set the resource's domain to PUBLIC_URL. Coolify gets a Let's Encrypt certificate.

Don't put it behind Cloudflare Access or Basic Auth. claude.ai can't log in through those; the Canvas login is the protection.

Settings (multi-user)

Env var

Default

Meaning

PUBLIC_URL

(required)

The server's public origin, no path, e.g. https://canvas.example.com. Must be https (http only for localhost testing).

CANVAS_MCP_KEY

(required)

Encrypts every login. At least 32 characters, random: openssl rand -hex 32. Changing it logs everyone out.

CANVAS_MCP_REDIRECT_HOSTS

claude.ai, claude.com, localhost

Comma-separated origins allowed to receive logins (the OAuth redirect targets of Claude apps). Leave it unset normally.

TRUST_PROXY

loopback, linklocal, uniquelocal

Addresses or subnets of the reverse proxies whose X-Forwarded-For is believed (Express "trust proxy"). The default covers a proxy on the same machine or a private network, such as Coolify's proxy or cloudflared. Use addresses, not true or a hop count: anything trusted can fake a client's IP and dodge the login limit.

CANVAS_MCP_ALLOW_PRIVATE_NETWORK

off

1 turns the network guard off, so logins can reach http and private addresses. For local testing only, never in production.

CANVAS_MCP_PORT / CANVAS_MCP_HOST

7341 / 127.0.0.1

Listen port and address. The Docker image uses 0.0.0.0.

CANVAS_MAX_CHARS

20000

Max characters per tool response chunk.

Security and limits

  • You're trusted with every student's Canvas token. It travels inside tokens encrypted with CANVAS_MCP_KEY that Claude holds. Nothing is written to disk, and tokens are never logged. Whoever runs the server can read them, and so can anyone who gets both the key and a student's token. A Canvas token can do anything the student can do in Canvas, even though this server only reads.

  • No per-student revoke on the server. A student cuts access off by deleting their token in Canvas (Account → Settings → Approved Integrations). Changing CANVAS_MCP_KEY logs everyone out at once.

  • Logins last until 90 days without use, or until the student's Canvas token expires or is deleted.

  • Run a single instance. One-time login codes are tracked in memory.

  • Rate limits. Logins: 10 attempts per 15 minutes per IP address, so a whole school behind one IP shares that. MCP requests: 120 per minute per student, at most 6 at a time per student and 16 at a time in all; past that, requests get a "slow down" or "server busy" error.

  • Signup is open. Anyone who can reach the server can log in with any Canvas address, including a fake one, and a hostile user can slow the service down for everyone (for example with a deliberately slow fake Canvas). If that happens, restart the server and change CANVAS_MCP_KEY.

  • Keep it off your own network. The server fetches whatever Canvas address a student types. It refuses private and internal addresses, but it can't know your own public IP: a hostname pointing there can reach your router's admin page or anything you port-forward. The public IPv6 addresses of devices on your LAN look public too. Run the container on a network that can't reach your LAN or router, for example a Docker network without IPv6 plus a firewall rule (Docker's DOCKER-USER chain) that drops its traffic to your LAN and your public IP.


Using it

Example requests:

  • "What's due this week across all my classes? Anything missing?"

  • "My AP Bio Unit 4 test is Tuesday. Make me a study guide from the actual slides and notes."

  • "Quiz me on the APUSH Period 5 material, one question at a time."

  • "Explain slide 12 of the cell respiration PowerPoint like I'm confused."

  • "What do I need on the final to keep an A in chemistry?"

  • "Where did I lose points on my last lab? Read the rubric feedback."

CLI reference

canvas-mcp [--url URL] [--token T] [--tz ZONE] [--max-chars N]      stdio mode (default)
canvas-mcp --http [--port 7341] [--host 127.0.0.1] [--secret S]     HTTP mode, one Canvas account (Option C)
PUBLIC_URL=… CANVAS_MCP_KEY=… canvas-mcp --http [--port] [--host]   HTTP mode, multi-user (Option D)
canvas-mcp --check                                                  test credentials
canvas-mcp --help | --version

Env var

Flag

Default

CANVAS_BASE_URL

--url

(required)

CANVAS_API_TOKEN

--token

(required; prefer the env var over the flag so the token doesn't land in shell history)

CANVAS_TZ

--tz

system time zone

CANVAS_MAX_CHARS

--max-chars

20000 characters per response chunk

MCP_SECRET

--secret

(required for single-user --http, minimum 24 chars)

CANVAS_MCP_PORT / CANVAS_MCP_HOST

--port / --host

7341 / 127.0.0.1 (Docker image uses 0.0.0.0)

Multi-user mode has its own settings (PUBLIC_URL, CANVAS_MCP_KEY, ...); see Option D.

Limitations

  • Scanned PDFs (images with no text layer) come back mostly empty, and the tool says so. Download the file and attach it to the chat so Claude can see the pages.

  • Quiz questions aren't visible to students through the API until results are released. That's Canvas's rule, not something this server can change.

  • Some schools hide tabs such as Files or Pages. Those tools return a 403/404, and Claude can work around it with list_modules.

  • Some schools disable personal access tokens entirely. If you can't make one, this approach won't work at your school.

Development

npm run dev     # tsc --watch
npm test        # unit tests, every tool against a mock Canvas API (stdio + HTTP), the multi-user login flow, docs checks

MIT licensed.

Related MCP Connectors

Related MCP Servers