Skip to main content
Glama
GodPuffin

Personal Canvas MCP

by GodPuffin
README.md
# Personal Canvas MCP

An MIT-licensed, single-user MCP server for student-visible [Canvas LMS](https://www.instructure.com/canvas) data. Each owner deploys their own copy to Vercel, keeps their Canvas personal access token in deployment secrets, and connects approved AI clients through OAuth.

The server is stateless: Canvas is queried on demand. There is no database, sync job, or content cache.

> **Personal/development use only.** Do not ask other people to paste Canvas personal access tokens into your deployment. A multi-user product must use institution-approved Canvas OAuth and comply with Instructure's [OAuth guidance](https://developerdocs.instructure.com/services/canvas/oauth2/file.oauth) and [API policy](https://www.instructure.com/policies/canvas-api-policy).

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FGodPuffin%2Fcanvas-mcp&project-name=personal-canvas-mcp&repository-name=personal-canvas-mcp&integration-ids=oac_7uYNbc9CdDAZmNqbt3LEkO3a&env=CANVAS_BASE_URL%2CCANVAS_ACCESS_TOKEN%2CCANVAS_PERMISSION_PRESET%2CMCP_OWNER_EMAIL%2CMCP_AUTH_MODE&envDefaults=%7B%22CANVAS_PERMISSION_PRESET%22%3A%22read%22%2C%22MCP_AUTH_MODE%22%3A%22clerk%22%7D&envDescription=Connect+your+personal+Canvas+account.+Vercel+provisions+Clerk+and+syncs+its+keys+automatically.+Never+share+these+secrets.&envLink=https%3A%2F%2Fgithub.com%2FGodPuffin%2Fcanvas-mcp%23clerk-oauth-recommended)

The main button deploys the recommended Clerk OAuth configuration. A [separate bearer-token Deploy Button](#static-bearer-token-optional) is available for clients that support custom authorization headers.

## What agents can access

The curated tools cover the connected owner's profile; courses, favorites, groups, activity and syllabi; assignments, differentiated due dates, rubrics, grades, missing work, submissions and feedback; calendar, planner and announcements; modules, pages, files and document extraction; discussions and visible replies; and classic/New Quiz data that Canvas actually reveals to a student.

Inbox conversations, recipient search, rosters, and standalone profiles for other students are deliberately absent. Discussion authors appearing in replies are the narrow exception. New Quiz endpoints vary by institution and student permissions, so unavailable detail is returned as a typed capability limitation. The server never attempts teacher-only quiz endpoints.

With `CANVAS_PERMISSION_PRESET=planner`, three additional tools create, update, and delete the owner's planner notes. Delete requires `confirm: true`. Assignment submission and course mutation tools do not exist.

## Deploy to Vercel

1. Click **Deploy with Vercel** above. Vercel clones this repository, creates the project, and requires its native Clerk Marketplace integration.
2. Enter the requested Canvas values. Only the non-sensitive settings `CANVAS_PERMISSION_PRESET=read` and `MCP_AUTH_MODE=clerk` are prefilled; no token, key, hostname, or email is placed in the button URL.
3. Complete the Clerk Marketplace provisioning step. Vercel creates a Clerk application and automatically syncs `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` into the project environments.
4. Deploy and open `/`. The page says whether configuration is ready without showing the Canvas hostname, email, or any secret.
5. If Vercel cannot supply `VERCEL_PROJECT_PRODUCTION_URL`, set `MCP_PUBLIC_URL` to the stable production origin and redeploy.

You can also fork the repository and import it through [Vercel's New Project flow](https://vercel.com/new) manually.

### Canvas credentials

Create a personal access token in your own Canvas account's **Account → Settings → Approved Integrations → New Access Token** area. Some institutions disable this feature or require administrator approval.

Set:

```dotenv
CANVAS_BASE_URL=https://school.instructure.com
CANVAS_ACCESS_TOKEN=your-personal-token
CANVAS_PERMISSION_PRESET=read
MCP_OWNER_EMAIL=you@example.com
```

`CANVAS_BASE_URL` must be an HTTPS origin. Tokens are sent only in the downstream Canvas `Authorization` header. They are never placed in URLs, MCP results, or operational logs.

## Authentication modes

`MCP_AUTH_MODE=clerk` is the recommended production mode and the mode that supports normal remote-MCP installation in ChatGPT and Claude. Authentication protects access to the deployment; it is separate from the Canvas token used downstream.

### Clerk OAuth (recommended)

The recommended Deploy Button installs Vercel's native Clerk integration, provisions a Clerk application, and syncs the publishable and secret keys. You do not paste those keys into the Deploy Button form. If you import the repository manually or deliberately use a separately managed Clerk application, configure the keys yourself:

1. Create a Clerk application and add its publishable and secret keys:

   ```dotenv
   MCP_AUTH_MODE=clerk
   NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
   CLERK_SECRET_KEY=sk_...
   ```

2. Whether Clerk was provisioned automatically or manually, open its Dashboard and enable OAuth for MCP, consent, and PKCE. Create the custom scopes `canvas:read` and `canvas:planner`. Prefer Client ID Metadata Documents (CIMD), and enable Dynamic Client Registration (DCR) only for older clients that require it; DCR exposes a public client-registration endpoint.
3. Configure the allowed account so its verified email exactly matches `MCP_OWNER_EMAIL`.
4. If the preset is `read`, clients need `canvas:read`. The `planner` preset requires both `canvas:read` and `canvas:planner`.

The Marketplace integration provisions and synchronizes credentials, but it cannot choose your MCP scopes, owner account, consent policy, or client-registration compatibility settings. Those remain one-time Clerk Dashboard steps. For a production Clerk instance, follow Clerk's domain setup instructions; a custom production domain may be required.

The app publishes RFC 9728 resource metadata at both:

```text
/.well-known/oauth-protected-resource
/.well-known/oauth-protected-resource/mcp
```

It also exposes Clerk-compatible authorization-server metadata at `/.well-known/oauth-authorization-server`. Invalid, expired, revoked, wrong-owner, or under-scoped tokens receive an OAuth bearer challenge before MCP executes.

### Static bearer token (optional)

For Codex, Cursor, VS Code, Claude Code, and other clients that can attach a custom header, Clerk can be omitted:

[![Deploy bearer-token mode with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FGodPuffin%2Fcanvas-mcp&project-name=personal-canvas-mcp&repository-name=personal-canvas-mcp&env=CANVAS_BASE_URL%2CCANVAS_ACCESS_TOKEN%2CCANVAS_PERMISSION_PRESET%2CMCP_OWNER_EMAIL%2CMCP_AUTH_MODE%2CMCP_ACCESS_TOKEN&envDefaults=%7B%22CANVAS_PERMISSION_PRESET%22%3A%22read%22%2C%22MCP_AUTH_MODE%22%3A%22token%22%7D&envDescription=Connect+your+personal+Canvas+account+and+set+a+random+32%2B+character+MCP+bearer+token.+Never+share+these+secrets.&envLink=https%3A%2F%2Fgithub.com%2FGodPuffin%2Fcanvas-mcp%23static-bearer-token-optional)

```dotenv
MCP_AUTH_MODE=token
MCP_ACCESS_TOKEN=a-random-secret-of-at-least-32-characters
```

Generate a secret with a cryptographically secure password manager or `openssl rand -hex 32`. Configure the client to send:

```http
Authorization: Bearer <MCP_ACCESS_TOKEN>
```

This mode has no OAuth discovery flow, so it is not installable through the ordinary ChatGPT or Claude remote-connector UI. It is intentionally useful for self-hosters whose client supports custom bearer headers.

Example Codex configuration:

```toml
[mcp_servers.canvas]
url = "https://your-project.vercel.app/mcp"
bearer_token_env_var = "PERSONAL_CANVAS_MCP_TOKEN"
```

### No authentication (local only)

`MCP_AUTH_MODE=none` works only when `NODE_ENV` is not `production`. A production deployment with this value fails closed. Do not expose an unauthenticated server to the internet.

## Local development

Requirements: Node.js 20.9 or newer and npm.

```bash
npm install
cp .env.example .env.local
npm run dev
```

On Windows PowerShell, replace the copy command with:

```powershell
Copy-Item .env.example .env.local
```

For the simplest local smoke test, set `MCP_AUTH_MODE=none`, start the app, and connect an MCP Inspector to `http://localhost:3000/mcp`. Restore `clerk` or `token` before any remote deployment.

## MCP behavior and safety

- The endpoint is stateless Streamable HTTP at `GET|POST|DELETE /mcp` and uses the Node.js runtime.
- Canvas IDs are requested and preserved as strings to avoid JavaScript integer precision loss.
- Every URL path is selected by a fixed tool implementation; there is no generic API-request tool.
- Pagination returns page/per-page/has-next metadata. Aggregate requests run sequentially to respect Canvas request-cost limits.
- `429` and transient `5xx` failures receive bounded exponential retries. Authentication, authorization, missing/expired resources, throttling, malformed responses, and unavailable capabilities have typed errors.
- Canvas HTML is converted to sanitized text. MCP results explicitly label Canvas content as untrusted external material.
- Logs are disabled in the MCP handler. If you add observability, record only redacted operation names, status, latency, and Canvas request cost—never request parameters or response bodies.

### File extraction limits

`canvas_extract_file` supports plain text, HTML, CSV, PDF, DOCX, PPTX, and XLSX. It does not support legacy DOC/PPT/XLS, OCR-only PDFs, encrypted/password-protected files, macros, or embedded executables.

- Source: 10 MiB maximum
- OOXML archive: 2,000 entries and 64 MiB expanded-data maximum before parsing
- Extracted source: 500,000 characters maximum
- Returned page: 20,000 characters by default, 50,000 maximum
- Continuation: pass the returned `nextOffset`

Signed download URLs are never returned. Downloaded bytes and extracted text live only for the current request.

## Verification

```bash
npm test
npm run typecheck
npm run lint
npm run build
npm audit
```

The automated suite covers origin validation, query encoding, string IDs, HTML and secret sanitization, pagination, retries, HTTP error mapping, optional bearer auth, permission-based registration, MIME spoofing, extraction continuation, and archive expansion limits.

Before relying on a deployment, also perform a live smoke test against a disposable Canvas course and use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector). Verify tool discovery, a cross-course overview, locked/empty/concluded course behavior, differentiated due dates, hidden grades, submission feedback, quiz visibility, file extraction, OAuth reconnect/revocation, and planner-note create/update/delete when enabled. Client-specific connection behavior should be checked in every client you intend to support.

## Future multi-user architecture

Canvas credential lookup is behind `CanvasCredentialProvider`. A future institution-approved OAuth implementation can replace the environment provider without changing tool handlers. That version will also need per-user encrypted token storage, refresh/revocation handling, tenant isolation, institutional developer-key approval, and an updated privacy/security review.

## License

[MIT](./LICENSE)

Maintenance

ActivityMaintained
ResponsivenessNo issues