Skip to main content

CanvasCtrl

CanvasCtrl is a local-first Canvas LMS toolkit with two authentication paths:

  • Browser session for schools that do not allow Personal Access Tokens (PATs). You complete normal SSO/MFA in visible Chrome; Canvas credentials are stored in macOS Keychain.
  • PAT for users whose Canvas account allows one. The token is read from standard input and stored in Keychain by the session MCP, while the original Python CLI remains compatible with its existing configuration.

The unified repository preserves the original CLI, local JSON vault, ask/chat agent, and read-only Python MCP while adding the session-backed MCP, direct live Canvas reads, file extraction, guarded uploads/submissions, full same-origin API access, and optional private Cloudflare mobile access.

The macOS installer also installs the bundled CanvasCtrl skill for Codex and Claude when it can do so without replacing a user-owned skill directory. The skill routes Canvas work through the MCP, materializes multi-file evidence in the private vault, and carries the quiz consent and New Quizzes boundary rules.

This unified build is currently an access-controlled source beta. The informational website is public; the repository and install artifacts remain private until a reviewed release is approved.

What it can do

Local vault and CLI

  • Mirror courses, assignments, classic quizzes, modules, module items, files, and announcements into owner-private JSON under ~/canvas-vault/.
  • Show today/upcoming work, changes, announcements, dashboards, and individual records.
  • Download course files and export due dates as an .ics calendar.
  • Keep the original Python vault, ask/chat, and vault-only MCP workflows available through canvasctrl-vault and the compatibility command canvasctl.

Live MCP

  • Read profiles, courses, syllabi, assignments, modules, pages, files, submissions, grades, calendars, todos, announcements, and discussions.
  • Extract bounded text from authorized PDF, HTML, and UTF-8 Canvas files without returning signed URLs.
  • Inspect a 164-operation catalog spanning 29 Canvas domains and invoke 73 enabled deterministic reads. The latest 21-read expansion covers course progress/settings/permissions, effective and differentiated dates, appointment groups, content shares, observer links, and richer self-submission details.
  • Use canvas_api_read for an arbitrary relative /api/v1/... or /api/quiz/v1/... route on the configured Canvas origin when a dedicated tool is unavailable.
  • Preview and submit supported file, text-entry, and URL coursework through dedicated state-bound workflows. File upload remains a separate approval before a later file submission.
  • Prepare and execute non-reserved same-origin Canvas API writes that the authenticated Canvas user is allowed to perform. Only allowlisted self-service routes use ordinary confirmed-write authorization; grading, enrollment, SIS, course/account administration, and unrecognized mutations require a separate locally approved privileged capability. Submissions, uploads, Classic Quiz attempts, and credential-bearing routes remain behind dedicated workflows or unavailable.
  • Run a documented Classic Quiz through one exact pre-start consent: the user says Yes, I want you to attempt this quiz., completes one native owner authentication, and that scoped session covers start, answer saves, and completion without per-question prompts.

Canvas—not CanvasCtrl—ultimately decides whether a route is available to a user, course, role, institution, or installed feature. New Quizzes does not expose a documented public student attempt lifecycle; CanvasCtrl does not bypass that boundary.

Write policy

Canvas writes are available but never automatic. A generic write requires all of these:

  1. The profile has explicitly enabled the confirmed-write scope.
  2. A preparation call produces an exact sanitized preview and one-time, short-lived confirmation.
  3. The MCP host asks the user before calling the confirmation tool.
  4. The local CanvasCtrl process asks macOS to authenticate the device owner for that exact action. Touch ID approves with a successful touch when available; macOS falls back to the Mac account password when Touch ID cannot be used.
  5. Only successful system authentication performs one request; cancellation, authentication failure, timeouts, mismatches, and retries fail closed.

CanvasCtrl uses macOS LocalAuthentication and receives only a success or failure; it never receives the fingerprint or Mac password. Depending on the user's Mac settings, macOS may also offer an approved Apple Watch. There is no unauthenticated button-only approval path.

Generic grading, enrollment, SIS, course/account administration, and unknown mutation routes additionally require canvasctrl authorize-privileged-writes. That profile-level grant has its own native authentication prompt, is never implied by ordinary confirmed-write authorization, and does not approve any later Canvas request; each privileged write still needs its own preview, chat confirmation, and native approval.

File upload preparation performs no Canvas write. Upload preflight and byte transfer happen only after native owner authentication. Uploading a file never submits coursework; file, text-entry, and URL submissions each have their own exact preview and authentication.

Classic Quiz attempts use a narrower workflow-specific gate. One exact preview and pre-start approval covers start, answer saves, and final completion only for the returned short-lived quiz session. It cannot authorize another quiz or attempt, does not expose Canvas's validation token, and never retries a mutation.

Architecture

CLI / AI client / mobile connector
              │
       deterministic tools
              │
     Canvas application services
       ├── local JSON vault
       ├── read and file service
       ├── guarded write service
       └── session/PAT broker
              │
     same-origin Canvas client
              │
        your Canvas account

The browser is used only for user-controlled authentication or reauthentication. Normal Canvas calls run through the standalone HTTP client.

See architecture.md, mcp.md, security.md, distribution.md, and the CanvasCtrl migration runbook.

Public install

Requirements:

  • macOS 13.5 or newer on Apple Silicon or Intel
  • Google Chrome for browser-session authentication
curl -fsSL https://canvasctrl.vivek-patel.com/install.sh | sh

The public bootstrap installs a private, pinned Node.js 24 LTS runtime under ~/.local/lib/canvasctrl, then installs a prebuilt CanvasCtrl runtime and universal Keychain and LocalAuthentication approval helpers. Both downloads are SHA-256 verified before activation. It does not use or alter a system Node.js installation and requires no npm, Homebrew, Apple Command Line Tools, Apple Developer account, or administrator access. At the end it asks for the school's bare HTTPS Canvas URL and saves that non-secret origin as the default profile; credentials and MCP client configuration remain untouched. Press Return to skip, or set CANVASCTRL_SKIP_ONBOARDING=1 for a noninteractive install. If an existing Codex configuration still launches an older source-tree build, the installer prints the exact launcher replacement and restart guidance without editing the file.

Updater-enabled releases check the signed stable channel on MCP start and then at most once every 24 hours while it remains running. A newer immutable runtime is downloaded, signature/checksum verified, validated, and atomically selected for the next MCP start. Canvas profiles, Keychain credentials, browser profiles, vault files, and MCP client configuration are outside the versioned application directory and remain unchanged. Existing pre-updater installations must run the public installer one final time to receive this bootstrap.

canvasctrl update check
canvasctrl update apply
canvasctrl update rollback
canvasctrl update channel stable
canvasctrl update automatic on

Development install

An approved source checkout retains the system-Node build path for contributors. It requires Node.js 20.16 or newer, npm, and Apple Command Line Tools; Python 3.10 or newer is needed only for the preserved legacy CLI/chat surface.

Run:

git clone "$CANVASCTRL_REPOSITORY_URL" canvasctrl
cd canvasctrl

./scripts/install-macos.sh

This developer installer builds and verifies both cores with the contributor's system Node.js, compiles the local Keychain and LocalAuthentication approval helpers, and installs an immutable runtime under ${CANVASCTRL_INSTALL_PREFIX:-$HOME/.local}/lib/canvasctrl. It offers the same local school-URL prompt, but does not edit an MCP client configuration or start authentication automatically.

Equivalent manual setup:

# Session MCP and unified TypeScript core
npm install
npm run build:native:macos
npm run build
npm_config_prefix="$HOME/.local" npm link

# Preserved Python CLI, vault, chat, and compatibility MCP
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[agent,mcp,dev]"

The unified TypeScript executable is canvasctrl. Compatibility launchers named canvas-mcp and canvasctl are retained when they do not overwrite a user-owned executable. The preserved Python surface installs as canvasctrl-vault; its former canvasctl command remains available for existing scripts. From that Python surface, live forwards to canvasctrl and mcp --live starts the unified MCP, while plain mcp starts the vault-only MCP.

Authentication

Browser session (no PAT)

canvasctrl setup --origin https://canvas.your-school.edu --auth session
canvasctrl login
canvasctrl status

The first school becomes the default, so later commands do not need --profile. setup reuses an existing profile with the same normalized Canvas origin instead of creating a second record or resetting its capabilities. Use canvasctrl setup --profile NAME --origin URL to add another account and canvasctrl set-default --profile NAME to switch the implicit school. canvasctrl profiles lists the configured choices.

You enter passwords and MFA only in visible Chrome. They are never accepted by an MCP tool or returned to an AI model. The saved session persists in macOS Keychain until Canvas expires/revokes it or you log out.

Personal Access Token

Pass the token through stdin, never the command line:

printf '%s' "$CANVAS_PAT" | canvasctrl setup \
  --origin https://canvas.your-school.edu \
  --auth pat \
  --pat-stdin
canvasctrl status

The token is stored in Keychain and is attached only to the configured Canvas origin. It is stripped from off-origin file-download requests and redirects.

Local MCP setup

canvasctrl serve --stdio

Claude Code:

claude mcp add canvasctrl -- canvasctrl serve --stdio

The public website also offers reviewed setup links for Codex/ChatGPT desktop and Claude Code, plus native MCP install links for Cursor and VS Code. Guided links prefill an installation task and do not execute it until the user sends the task and approves the commands. Cursor and VS Code links add only the local stdio configuration, so run the installer first. Other local MCP clients can download the generic configuration from:

https://canvasctrl.vivek-patel.com/canvasctrl-mcp.json

ChatGPT web, Claude.ai, and mobile clients cannot reach a local stdio process. They require an optional user-owned remote gateway; the public distribution never embeds the maintainer's Cloudflare endpoint or credentials.

Claude Desktop configuration:

{
  "mcpServers": {
    "canvasctrl": {
      "command": "/absolute/path/to/canvasctrl",
      "args": ["serve", "--stdio"]
    }
  }
}

For the preserved Python vault-only MCP, use canvasctrl-vault mcp; existing canvasctl mcp configurations remain supported.

Enabling writes

Writes start disabled. Explicitly enable confirmation-gated Canvas API writes:

canvasctrl authorize-confirmed-writes

This permits authorized Classic Quiz actions and other same-origin API writes. Generic mutations still require their own short-lived preview, explicit user confirmation, and native owner-authentication prompt. A Classic Quiz instead requires one exact approval before the attempt starts; that scoped session covers its answer saves and completion without prompting on every question.

This ordinary authorization never enables generic grading, enrollment, SIS, or course/account-administration mutations. When a user with the necessary Canvas role intentionally needs those routes, they must separately run:

canvasctrl authorize-privileged-writes

The capability grant performs no Canvas write and requires its own native device-owner authentication prompt. Every later privileged request remains one-time, previewed, confirmed, natively approved, and subject to Canvas permissions.

Text-entry and URL coursework submissions are enabled by authorize-confirmed-writes and use dedicated prepare/confirm tools. They do not need a staged file, but still require an exact preview, explicit confirmation, native owner authentication, and post-write verification. File uploads and file-based coursework submissions additionally require a one-time upload verification. Use the actual profile name shown by canvasctrl profiles:

CANVAS_PROFILE_NAME=your-school
mkdir -p "$HOME/Documents/Canvas MCP/Uploads/$CANVAS_PROFILE_NAME"
cp /path/to/a/test-file.pdf "$HOME/Documents/Canvas MCP/Uploads/$CANVAS_PROFILE_NAME/"

canvasctrl verify-upload \
  --profile "$CANVAS_PROFILE_NAME" \
  --course-id 12345 \
  --source "$HOME/Documents/Canvas MCP/Uploads/$CANVAS_PROFILE_NAME/test-file.pdf"

The verification upload itself requires native device-owner authentication and creates a file in the selected course Files area. Use a harmless test file and course. The command does not submit an assignment.

canvasctrl doctor checks the native helper and macOS owner-authentication availability without opening a prompt. canvasctrl test-approval-dialog starts a harmless local system-authentication test that never contacts Canvas or authorizes a future write. Canceling it is a denial. A connected MCP client can call canvas_get_runtime_info to verify the server version, selected profile, exposure, and whether the native approval broker is actually attached.

Private mobile access

Optional remote mode uses a tunnel initiated by the user's Mac and a Cloudflare Access JWT restricted to one email, one device identity, and one Canvas profile. Canvas credentials never go to Cloudflare or the mobile MCP client. The Mac must remain awake and online.

This project does not ship the maintainer's hostname, tunnel token, Access audience, account ID, credentials, or Canvas data. Each installer must configure their own endpoint. Remote mode is opt-in and read-only unless the server is explicitly started with --confirmed-writes; even then, writes still require successful device-owner authentication on the Mac.

See mcp.md for the full commands and boundaries.

Verification

npm run typecheck
npm test
uv run --with pytest --with pytest-cov --with responses pytest -q
npm run privacy:check
npm run website:check
npm run distribution:check

Privacy summary

  • No CanvasCtrl-hosted backend is required.
  • Session cookies and PATs remain in the local OS credential vault.
  • Course data and downloaded files are private local files with owner-only permissions.
  • Signed file URLs, cookies, CSRF values, upload parameters, and authentication headers are removed from MCP results and safe errors.
  • AI clients receive only the Canvas data needed for requested tool results. If you use the original BYOK chat agent, its prompt and selected tool results go directly to the AI provider you configured.
  • The optional Cloudflare tunnel transports MCP requests to your own Mac; it does not store or distribute Canvas credentials.
  • Repository privacy checks reject maintainer-specific identifiers and common secret patterns.

Read security.md before enabling remote access or writes.

License and disclaimer

MIT © 2026 CanvasCtrl contributors.

CanvasCtrl is an independent, unofficial tool. It is not affiliated with, endorsed by, or sponsored by Instructure, Inc. Canvas and Instructure are trademarks of Instructure, Inc.

Release files for canvasctrl 0.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for canvasctrl 0.4.1
File Size Uploaded
canvasctrl-0.4.1.tar.gz 62.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for canvasctrl 0.4.1
File Interpreter ABI Platform
canvasctrl-0.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 121.9 kB

Release files / canvasctrl-0.4.1.tar.gz

Download URL canvasctrl-0.4.1.tar.gz
Size 62.6 kB
Tags Source
SHA-256 checksum
How to use checksums
aa0fbb8a1ff9ba173a96dab5daa4b3bb443e57c2fb453ec40350c447539752e4
BLAKE2b-256 checksum
How to use checksums
f9e707e45edce8ed5bb49d8133e0f29e26e528ae4f2619d5de5c845a9d1712fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / canvasctrl-0.4.1-py3-none-any.whl

Download URL canvasctrl-0.4.1-py3-none-any.whl
Size 59.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e70623e5cc47d2039282117165da3ebc95998d757342a80d554079fca32efb0b
BLAKE2b-256 checksum
How to use checksums
3b2fbfbb7133be3b319c545d3506e2892c5df0466c3722f533ad8f185f8b7393
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.2

2 release files

This release

0.4.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page