Canvas MCP
README.md
# Canvas MCP
MCP server that exposes Canvas LMS as tools — courses, modules, files, pages,
assignments, submissions/grades, announcements, upcoming deadlines, and syllabus.
Designed to be consumed by Ada (chat tool loop / edge functions) and any other
MCP client (Claude Desktop, Cursor, etc.).
## Setup
```bash
cd mcps/canvas
npm install
npm run build
```
Create `.env` (or pass through your MCP client config):
```env
CANVAS_BASE_URL=https://canvas.asu.edu/api/v1
CANVAS_TOKEN=your_canvas_personal_access_token
```
Generate the token in Canvas: **Account → Settings → New Access Token**.
## Run
Stdio transport (default for MCP clients):
```bash
CANVAS_BASE_URL=... CANVAS_TOKEN=... node dist/index.js
```
## Tools
| Tool | Purpose |
|------|---------|
| `list_courses` | Active enrollments with term + dates |
| `get_course` | Single course incl. syllabus body |
| `list_modules` | Modules with items inlined |
| `list_module_items` | Items in one module |
| `get_file_metadata` | File info + download URL |
| `get_file_text` | Download file body as UTF-8 text (truncated) |
| `list_pages` / `get_page` | Wiki pages |
| `list_assignments` / `get_assignment` | Assignments by due date |
| `list_my_submissions` | Current student's grades + late/missing |
| `list_announcements` | Announcements across courses |
| `list_upcoming` | Upcoming events for the user |
| `get_syllabus` | Syllabus HTML |
## Claude Desktop config
```json
{
"mcpServers": {
"canvas": {
"command": "node",
"args": ["/absolute/path/to/ada/mcps/canvas/dist/index.js"],
"env": {
"CANVAS_BASE_URL": "https://canvas.asu.edu/api/v1",
"CANVAS_TOKEN": "..."
}
}
}
}
```
## Cloudflare Workers (HTTP transport)
`src/worker.ts` exposes the same toolset over HTTP for hosting on Cloudflare
Workers. Deploy with:
```bash
npx wrangler deploy
```
Set the secrets once via `wrangler secret put`:
```bash
echo "https://canvas.asu.edu/api/v1" | npx wrangler secret put CANVAS_BASE_URL
echo "your_canvas_token" | npx wrangler secret put CANVAS_TOKEN
```
The Worker accepts JSON-RPC `tools/list` and `tools/call` POSTs.
**Multi-tenant headers** (override env per request — Ada uses these):
```http
Authorization: Bearer <user's canvas PAT>
X-Canvas-Base-Url https://canvas.<institution>.edu/api/v1
X-Ada-Service-Key <ADA_SERVICE_KEY> # required when env.ADA_SERVICE_KEY is set
```
When no headers are present, the worker falls back to the `CANVAS_BASE_URL` /
`CANVAS_TOKEN` secrets (single-tenant mode). Set `ADA_SERVICE_KEY` to gate
header-based requests behind a shared secret:
```bash
echo "$(openssl rand -hex 32)" | npx wrangler secret put ADA_SERVICE_KEY
```
## Notes
- Canvas pagination is followed automatically via the `Link` header up to per-call caps.
- `get_file_text` decodes as UTF-8; binary formats (PDF, DOCX) need upstream extraction.
- Single-tenant by env var. For multi-user (Ada), spawn one process per user
*or* swap stdio for an HTTP transport that accepts a per-request token.
TDQS
B3.4/5.0
Scored across 15 tools
Disambiguation5/5
Each tool targets a distinct resource (course, assignment, page, file, etc.) or operation (list vs. get), with clear boundaries. No two tools have overlapping purposes.
Naming Consistency4/5
Most tools follow a consistent verb_noun pattern (get_*, list_*), but 'whoami' breaks the pattern. However, this is a common convention and does not cause confusion.
Tool Count5/5
15 tools is well within the ideal range (3-15). Each tool serves a clear purpose for student interaction with Canvas, neither too many nor too few.
Completeness5/5
The tool set covers all essential student-facing operations: viewing courses, assignments, submissions, pages, modules, files, announcements, syllabus, and upcoming events. No obvious gaps given the read-only student role.
Maintenance
ActivityInactive
ResponsivenessNo issues