@mikael_david/canvas-mcp
v0.2.4
Published
MCP server for Canvas LMS — list weekly agenda, read assignments, submit files/text, post on discussions
Maintainers
Readme
canvas-mcp
A Model Context Protocol (MCP) server that turns the Canvas LMS API into a small, well-typed toolbox an LLM can actually use.
Built around one principle: never confuse "this assignment needs a submission" with "I already submitted". Every tool that returns an assignment surfaces those as two separate fields.
What it can do
| Tool | What it does |
|---|---|
| canvas_me | Authenticated user (sanity check that the token works) |
| canvas_courses | List active courses with ids, codes and dates |
| canvas_week | Headline tool: list every planner item in a date range with explicit requires_submission, submission_status, due_at and accepted_submission_types. Defaults to the next 7 days. |
| canvas_todo | Items Canvas thinks need user action right now |
| canvas_assignment | Full assignment + my current submission state, in one call. Description converted to Markdown. Accepts a Canvas URL or course_id + assignment_id. |
| canvas_submit_file | Three-step Canvas file upload (request URL → upload binary → confirm) wrapped in a single call |
| canvas_submit_text | Submit a text answer for online_text_entry |
| canvas_submit_url | Submit a URL for online_url |
| canvas_discussion | Fetch a discussion topic with the full entry tree + participant names + Markdown |
| canvas_post_to_discussion | Create a top-level entry on a topic (forum answer) |
| canvas_reply_to_entry | Reply to a peer's entry (forum comment) |
| canvas_grades | My current and final score per course |
All endpoints that take a Canvas resource accept either an explicit pair of ids or a full Canvas URL like https://lms.jala.university/courses/700/assignments/13882. Just paste it in.
Requirements
- Node 20 or newer
- A Canvas Personal Access Token (Account → Settings → New Access Token)
Install
Looking for a step-by-step in Brazilian Portuguese? See
GUIDE.md. Want to point an AI assistant (Gemini CLI, Cursor, Cline, Claude Code) at this server? SeeAGENTS.md.
Option 1 — npx (recommended)
The server is published on npm. The MCP client launches it on demand, so there is nothing to install ahead of time. Just reference it in your client config (see Wire it into Claude Code).
Option 2 — Global install
npm install -g @mikael_david/canvas-mcp
canvas-mcp --help # confirms the binary is on PATHOption 3 — From source
git clone https://gitlab.com/mikaeldavidlopes/canvas-mcp.git
cd canvas-mcp
pnpm install # or: npm install
pnpm build # or: npm run buildGet a Canvas Personal Access Token
The server never knows or asks for your password — it talks to Canvas with a token tied to your account.
- Open Canvas (e.g.
https://lms.jala.university) and log in. - Click your avatar → Account → Settings.
- Scroll to Approved Integrations → + New Access Token.
- Purpose:
canvas-mcp. Expiration: leave blank for no expiry, or pick a date. - Copy the token shown once — Canvas will not show it again.
Configure credentials
The server reads credentials from, in order:
- Environment variables
CANVAS_BASE_URL+CANVAS_API_TOKEN. - JSON file at the path in
CANVAS_CREDENTIALS_FILE. - JSON file at
~/.openclaw/canvas_credentials.json.
The JSON file looks like:
{
"base_url": "https://lms.jala.university",
"token": "your_personal_access_token_here"
}A .env.example is provided for the env-var path. Whichever option you pick, the token stays on your machine and is never logged.
Wire it into Claude Code
Easiest path, using the CLI:
claude mcp add --scope user canvas \
-e CANVAS_BASE_URL=https://lms.jala.university \
-e CANVAS_API_TOKEN=your_personal_access_token_here \
-- npx -y @mikael_david/canvas-mcpOr edit ~/.claude.json (user scope) / .mcp.json (project scope) directly:
{
"mcpServers": {
"canvas": {
"command": "npx",
"args": ["-y", "@mikael_david/canvas-mcp"],
"env": {
"CANVAS_BASE_URL": "https://lms.jala.university",
"CANVAS_API_TOKEN": "your_personal_access_token_here"
}
}
}
}If you installed from source, swap the command:
"command": "node",
"args": ["/absolute/path/to/canvas-mcp/dist/index.js"]After saving, restart Claude Code and run /mcp to confirm canvas shows as Connected.
Wire it into Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on your platform:
{
"mcpServers": {
"canvas": {
"command": "npx",
"args": ["-y", "@mikael_david/canvas-mcp"],
"env": {
"CANVAS_BASE_URL": "https://lms.jala.university",
"CANVAS_API_TOKEN": "your_personal_access_token_here"
}
}
}
}Try it without an MCP client
A smoke test exercises the read-only tools against the live API:
pnpm tsx scripts/smoke-test.tsIt prints the first ~600 characters of each response, so you can confirm the token works and the data looks right before plugging the server into a client.
Design notes
- The submission ambiguity, solved.
canvas_weekandcanvas_assignmentboth returnrequires_submission(derived fromsubmission_types) andsubmission_status(derived from the workflow state). Callers never have to guess what the columns mean. - HTML to Markdown. Canvas serves HTML in assignment descriptions and discussion entries. Every text field passes through Turndown so LLMs read it cleanly, without
<p>and<span>everywhere. - URL parsing. Every resource-bound tool also accepts the full Canvas URL. Pasting URLs is the most natural path when the LLM is reasoning about an assignment.
- No quiz submission. Listing quizzes works through
canvas_week, but actually answering a quiz needs the dynamic question flow which is out of scope for this MVP. Read-only is fine for now. - Credentials are never logged. Errors include the path and status code, never the token.
Project layout
canvas-mcp/
├── src/
│ ├── index.ts MCP server entry (stdio)
│ ├── client.ts HTTP client with pagination + 3-step file upload
│ ├── auth.ts Credential resolution (env / file / default path)
│ ├── tools.ts The 11 tools
│ ├── types.ts Canvas API shapes the MCP exposes
│ └── utils/
│ ├── html.ts HTML → Markdown via Turndown
│ ├── pagination.ts Link header parser
│ └── url.ts Canvas URL parser
├── scripts/
│ └── smoke-test.ts Read-only sanity check against the live API
├── package.json
├── tsconfig.json
├── tsup.config.ts
└── README.mdSharing with classmates
This server has no shared state and stores no credentials. Anyone with a Canvas account (any instance) can use the same npm package.
The shortest pitch to a classmate:
- Send them the package name:
@mikael_david/canvas-mcp. - Point them at
GUIDE.md(Brazilian Portuguese, end-to-end walkthrough including how to create the Canvas token). - They run the
claude mcp addcommand, restart Claude Code, and they're done.
What stays personal: each person uses their own Canvas token, and Canvas filters everything by token owner. Course list, grades, planner, submissions — all scoped to the individual.
What is shared safely: the code itself.
If a classmate is on a different Canvas (e.g. https://canvas.instructure.com), they just change CANVAS_BASE_URL. The same 12 tools work.
License
MIT.
