Canvas MCP Server
An MCP (Model Context Protocol) server that exposes UBC Canvas LMS data as tools consumable by Claude Desktop, Claude Code, n8n AI Agent nodes, or any MCP-compatible client.
AI Agent / Claude Desktop / n8n
│ MCP tool calls
▼
canvas-mcp (this server)
│ REST
▼
https://ubc.instructure.com/api/v1/
This server is read-only. It surfaces Canvas data; it never writes, drafts, or submits anything.
---
Prerequisites
- Node.js 18 or higher (or Docker — see below)
- A UBC Canvas personal access token (see below)
---
Token Generation
- Log in to Canvas at https://ubc.instructure.com
- Click your avatar (top-left) → Account → Settings
- Scroll to Approved Integrations → click + New Access Token
- Give it a descriptive purpose (e.g. "MCP Server")
- Copy the token — it will not be shown again
Security note: This token can read your grades, submissions, and course communications. Never share it, never commit it, and revoke it immediately if your machine is compromised.
---
Setup
# 1. Clone the repository
git clone <repo-url>
cd Canvas-MCP-Server
# 2. Install dependencies
npm install
# 3. Configure environment
cp .env.example .env
# Edit .env and paste your token:
# CANVAS_TOKEN=your_token_here
# CANVAS_BASE_URL=https://ubc.instructure.com/api/v1
# 4. Build
npm run build
# 5. Verify your token works
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' | node dist/index.js
---
Available Tools
| Tool | Description | |------|-------------| | whoami | Verify your token and return your Canvas profile (name, email, login ID) | | list_courses | List all active courses. Returns course IDs required by other tools | | list_assignments | List upcoming assignments for a course (default: next 14 days, max 90) | | get_assignment | Full assignment details with plain-text description (HTML stripped) | | list_announcements | Recent announcements from one or more courses (default: last 14 days) | | list_upcoming | Unified calendar view of upcoming assignment due dates across all courses | | get_submission | Your submission status for an assignment: score, grade, late/missing flags |
---
Fresh Ubuntu Setup (Docker)
Follow these three steps on a brand-new Ubuntu machine. No Node.js installation needed.
Step 1 — Install Docker Engine
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Allow running Docker without sudo:
sudo usermod -aG docker $USER
newgrp docker # apply group change in current shell without logging out
docker run hello-world # confirm Docker is working
Step 2 — Clone the repo and set your token
git clone https://github.com/terraceonhigh/Canvas-MCP-Server.git
cd Canvas-MCP-Server
cp .env.example .env
nano .env # paste your CANVAS_TOKEN value
Step 3 — Build the image and verify
docker build -t canvas-mcp .
# Smoke-test: should print a valid JSON-RPC response to stdout
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
| docker run --rm -i \
-e CANVAS_TOKEN=$(grep CANVAS_TOKEN .env | cut -d= -f2) \
-e CANVAS_BASE_URL=https://ubc.instructure.com/api/v1 \
canvas-mcp
The token is read from
.envonly for this test command and passed via-eat runtime — it is never baked into the image.
---
Docker
You can run the server in a container instead of installing Node.js locally.
# Build the image
docker build -t canvas-mcp .
# Verify your token (one-shot test)
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
| docker run --rm -i \
-e CANVAS_TOKEN=your_token_here \
-e CANVAS_BASE_URL=https://ubc.instructure.com/api/v1 \
canvas-mcp
The container reads MCP messages from stdin and writes responses to stdout, so always pass -i to docker run. Never use -t (TTY), as it would corrupt the binary stdio stream.
Claude Desktop with Docker
{
"mcpServers": {
"canvas": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-e", "CANVAS_TOKEN=your_token_here",
"-e", "CANVAS_BASE_URL=https://ubc.instructure.com/api/v1",
"canvas-mcp"
]
}
}
}
---
Claude Desktop Configuration
Add this to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"canvas": {
"command": "node",
"args": ["dist/index.js"],
"cwd": "/absolute/path/to/Canvas-MCP-Server",
"env": {
"CANVAS_TOKEN": "your_token_here",
"CANVAS_BASE_URL": "https://ubc.instructure.com/api/v1"
}
}
}
}
Replace /absolute/path/to/Canvas-MCP-Server with the actual path on your machine.
---
n8n AI Agent Node
In any n8n AI Agent node:
- Add a new MCP Tool credential
- Set the command to
nodeand args to["dist/index.js"] - Set the working directory to this project's path
- Set
CANVAS_TOKENandCANVAS_BASE_URLas environment variables
The agent can then call tools like list_assignments, filter results, and pipe them to downstream services (task managers, calendars, notification systems) in the same workflow.
---
Architecture
src/
├── index.ts # MCP server entry point — registers all tools
├── canvas-client.ts # Authenticated fetch wrapper with automatic pagination
└── tools/
├── courses.ts # list_courses
├── assignments.ts # list_assignments, get_assignment
├── announcements.ts# list_announcements
├── calendar.ts # list_upcoming
└── submissions.ts # get_submission, whoami
Key design decisions:
- Pagination is automatic — all list endpoints follow
Link: rel="next"headers until exhausted - HTML is always stripped — descriptions and announcement bodies are returned as clean plain text
- Token is never logged — the
Authorizationheader is excluded from all error messages and debug output - Stdout is sacred — all diagnostic output goes to stderr; stdout carries only MCP protocol messages
---
Known Limitations
- Rate limits: Canvas enforces undocumented rate limits. Polling workflows should add delays between requests if 403s appear.
- Token scope: A personal token reads everything you can see in Canvas. Treat it like a password.
- Announcement interpretation: Pattern-matching (e.g. detecting class cancellations) is the consuming agent's job — this server returns clean text only.






