Skip to main content
Glama
README.md
# canvas-control

`canvas-control` turns Canvas LMS into a fast, scriptable download pipeline and exposes it to AI assistants via MCP.

- **Download** files from multiple Canvas content sources in one command
- **Sync** course files like `git pull` — skip unchanged, re-download on demand
- **Check grades** across all courses from the terminal or export to CSV/JSON
- **Submit assignments** from the terminal (file upload, text entry, URL)
- **Talk to Canvas** through AI assistants (Claude Desktop, Cursor, Claude Code) — search files, download by name or type, sync courses, and set paths in natural language

## Star History

[![Star History Chart](https://api.star-history.com/svg?repos=tomtranjr/canvas-control&type=date&legend=top-left)](https://www.star-history.com/#tomtranjr/canvas-control&type=date&legend=top-left)

## Table of contents

- [Why canvas-control](#why-canvas-control)
- [Quick start](#quick-start)
- [MCP server (AI assistants)](#mcp-server-ai-assistants)
- [CLI highlights](#cli-highlights)
- [Documentation](#documentation)
- [Dev Testing](#dev-testing)
- [Contributing](#contributing)

## Why canvas-control

- One command downloads from `files`, `assignments`, `discussions`, `pages`, and `modules`.
- Built for repeatable workflows: predictable output paths, machine-readable manifests, idempotent re-runs.
- Guided mode (`download interactive`) for beginners, fully scripted mode (`download run`) for power users.
- Grades accessible from the terminal: summaries, per-assignment breakdowns, CSV/JSON export.
- MCP server lets AI assistants query courses, grades, assignments, and sync files with natural language.

## Quick start

`canvas-control` uses [uv](https://docs.astral.sh/uv/) for environment and dependency management.

1. Create and activate a virtual environment (Python 3.12+):

```bash
uv venv --python 3.12
source .venv/bin/activate
```

2. Install the project and dev dependencies:

```bash
uv pip install -e '.[dev]'
```

3. Set your Canvas base URL once:

```bash
cvsctl config set-base-url https://your-school.instructure.com
```

4. Set `CANVAS_TOKEN` (see [configuration docs](docs/configuration.md#set-canvas_token)) or let `cvsctl` prompt for it.

5. Run the onboarding wizard to configure everything interactively, or jump straight to your first command:

```bash
# Guided setup (recommended for first-time users)
cvsctl onboard

# Or go straight to listing your courses
cvsctl courses list
```

## MCP server (AI assistants)

`canvas-control` includes an MCP (Model Context Protocol) server so you can interact with Canvas through AI assistants using natural language.

### Available tools


| Tool                       | Description                                                        |
| -------------------------- | ------------------------------------------------------------------ |
| `list_courses`             | List enrolled courses (active or all)                              |
| `get_upcoming_assignments` | Assignments due within a time window                               |
| `get_announcements`        | Recent course announcements                                        |
| `get_calendar_events`      | Calendar events within a time window                               |
| `get_syllabus`             | Course syllabus content                                            |
| `get_grades_summary`       | Grade overview across courses                                      |
| `get_grades_detailed`      | Per-assignment grade breakdown                                     |
| `list_course_files`        | List all files in a course (raw)                                   |
| `search_course_files`      | Search files by name, type, or folder — preview before downloading |
| `download_file`            | Download a single file by ID                                       |
| `download_selected_files`  | Download a batch of specific files to a local directory            |
| `set_download_path`        | Save a download path to config (global or per-course)              |
| `complete_assignment`      | Mark assignment complete (submission or module completion flow)    |
| `sync_course_files`        | Sync all course files to local disk; supports custom `destination` |


### Natural language file downloads

Three new tools enable a conversational download workflow directly from Claude Desktop or Cursor:

`**search_course_files**` — search before you download. Filter by name substring, file extension, or folder path. The assistant shows you a preview of matching files so you can confirm before anything hits disk.

`**download_selected_files**` — download a batch of specific files (by Canvas file ID) to any local directory. Skips files that already exist, so it's safe to re-run. Returns a per-file status: `downloaded`, `skipped`, or `failed`.

`**set_download_path**` — persist a directory path to config so you don't have to specify it every time. Set a global default or a per-course path.

`**sync_course_files**` — now accepts an optional `destination` parameter, so you can tell the assistant exactly where to put everything without touching config first.

Example conversation:

```
You: Search for PDF files in my Biology course
Claude: Found 8 PDFs — Lecture 1.pdf, Lecture 2.pdf, Syllabus.pdf …

You: Download those to ~/Documents/Bio
Claude: Downloaded 7, skipped 1 (already exists). Saved to ~/Documents/Bio.

You: Save that as my default path for Biology
Claude: Saved ~/Documents/Bio as the download path for Biology (course 12345).
```

### Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "canvas": {
      "command": "uv",
      "args": ["--directory", "/path/to/canvas-control", "run", "cvsctl", "mcp", "serve"],
      "env": {
        "CANVAS_TOKEN": "your-token",
        "CANVAS_BASE_URL": "https://your-school.instructure.com",
        "CANVAS_TIMEZONE": "America/Los_Angeles"
      }
    }
  }
}
```

### Cursor

Add to `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally:

```json
{
  "mcpServers": {
    "canvas": {
      "command": "uv",
      "args": ["--directory", "/path/to/canvas-control", "run", "cvsctl", "mcp", "serve"],
      "env": {
        "CANVAS_TOKEN": "your-token",
        "CANVAS_BASE_URL": "https://your-school.instructure.com",
        "CANVAS_TIMEZONE": "America/Los_Angeles"
      }
    }
  }
}
```

### Claude Code

```bash
claude mcp add canvas -- uv --directory /path/to/canvas-control run cvsctl mcp serve
```

Set `CANVAS_TOKEN`, `CANVAS_BASE_URL`, and optionally `CANVAS_TIMEZONE` in your shell profile or `.envrc`.

### Example prompts

Courses, grades, and assignments:

- "What classes am I taking?"
- "What assignments are due this week?"
- "Show my grades for Biology"
- "Are there any new announcements?"
- "Mark Homework 2 complete"

Downloading files:

- "Search for slides in my CS101 course"
- "Download the lecture PDFs from my Biology course to ~/Documents/Bio"
- "Save ~/Documents/Bio as my default download path for Biology"
- "Sync all files from my Time Series course to ~/Documents/School"
- "Re-download all files for Biology, overwriting existing ones"

## CLI highlights

Download all files for a course:

```bash
cvsctl download run --course 12345
```

View grades at a glance:

```bash
cvsctl grades summary
```

Export grades to CSV:

```bash
cvsctl grades export --detailed
```

Guided interactive download:

```bash
cvsctl download interactive
```

Submit an assignment:

```bash
cvsctl assignments submit --course 12345 --assignment "Homework 1" --file ./solution.py
```

See [CLI Reference](docs/cli-reference.md) for the full command tree and all options.

## Documentation

- [Configuration](docs/configuration.md) — token setup, download paths, per-course paths
- [CLI Reference](docs/cli-reference.md) — full command tree and behavior notes
- [Guides](docs/guides.md) — workflows, grades, interactive mode, troubleshooting

## Dev Testing

When changes are merged into the main branch, update your local clone and reinstall so the MCP server picks up the latest code.

1. Pull the latest changes:

```bash
git pull origin main
```

2. Reinstall the package (picks up new dependencies or entry-point changes):

```bash
uv pip install -e '.[dev]'
```

3. Run the test suite to verify nothing is broken:

```bash
uv run pytest
```

4. Restart the MCP server in your AI client so it spawns a fresh process:
  - **Claude Desktop**: quit and relaunch the app
  - **Cursor**: open Settings → MCP and click the refresh/reconnect button
  - **Claude Code**: the server is spawned per-session; start a new session

## Contributing

1. Create a branch for your change.
2. Implement focused changes and tests.
3. Run tests:

```bash
uv run pytest
```

4. Optional live smoke test (requires real Canvas credentials):

```bash
export CANVAS_BASE_URL="https://your-school.instructure.com"
export CANVAS_TOKEN="your-token"
export CANVAS_TEST_COURSE_ID="12345"
uv run pytest -m live
```

5. Open a PR with what changed, why, and test coverage.

TDQS

A3.7/5.0

Scored across 14 tools

Disambiguation4/5

Tools are mostly distinct, but download_file and download_selected_files overlap in purpose; descriptions help clarify. Similarly, sync_course_files could be confused with bulk download. Overall, most tools have clear boundaries.

Naming Consistency5/5

All tools follow verb_noun snake_case pattern consistently. Verbs are descriptive (get, list, download, complete, set, sync). No mixing of conventions.

Tool Count5/5

14 tools is appropriate for a Canvas LMS integration. Each tool covers a key feature area without unnecessary duplication.

Completeness4/5

Covers core Canvas features: courses, files, assignments, grades, announcements, calendar, syllabus. Missing individual assignment details and submission file upload, but complete_assignment handles submission with guidance. Minor gaps exist but a typical workflow can be completed.

Maintenance

ActivityInactive
ResponsivenessNo issues