Install
How to install and configure the Canvas LMS MCP server, including token creation.
Prerequisites
- Python 3.11+ — the server is a Python package, run via
uvx. - Your Canvas base URL — the address you normally log in at, without any path.
For NUS that's
https://canvas.nus.edu.sg. - A Canvas access token — walkthrough below.
This is personal-use software: your token, on your machine, reaching only your own Canvas account. See Compliance for what that means and why.
Get your Canvas access token
Canvas has no "log in with Canvas" flow for locally-installed tools, so you create a token yourself once and paste it into your AI client's config. It takes about a minute.
Open your Canvas account settings
Go to https://<your-canvas>/profile/settings directly — for NUS that's
canvas.nus.edu.sg/profile/settings.
Or click through: Account in the left sidebar → Settings.
Scroll to "Approved Integrations"
It's near the bottom, below Web Services. You'll see a table of apps you've already
authorised — things like Canvas for iOS or Panopto — and a + New access token
button underneath it.
No "Approved Integrations" section, or no button? Your institution has disabled student token creation. Nothing in this guide will work, and there's no workaround — ask your IT service desk whether API access tokens can be enabled for your account.
Click "+ New access token"
Fill in the two fields:
| Field | What to put |
|---|---|
| Purpose | Something you'll recognise later, e.g. canvas-api-mcp |
| Expires | A date. See below, it is probably not optional for you |
Your token will expire, and you cannot turn that off. Since Instructure's October 2025 security update, an account holding only student roles must set an expiry date no more than 120 days out. Institutions can and do enforce shorter caps, so check the maximum your own Canvas offers when you pick the date. NUS, for example, allows 90 days.
Write the expiry date down somewhere. This is the single most likely reason the server stops working weeks from now, and an expired token looks like a broken install rather than an expired credential unless you are expecting it.
If your account also holds a teacher or TA role somewhere, the cap may not apply and you may still see a blank option. Set a date anyway. A token that never expires is convenient right up until it leaks.
Copy the token immediately
Canvas shows the token exactly once. Close the dialog without copying it and you cannot retrieve it — you'll have to delete it and start again.
It looks like a long string beginning with a number and a tilde:
7~aBcDeF1234567890aBcDeF1234567890aBcDeF1234567890aBcDeF1234Paste it straight into your client config in the next section. Don't put it in a note, a chat, or a file you might commit.
Treat this like your password. The token can read your grades, your submissions and your private instructor messages, and can submit work as you. It is not scoped and Canvas cannot restrict what it reaches. Anyone holding it is you, as far as the API is concerned — so never paste it into a shared repo, an issue, or a screenshot.
Revoke one any time from the same Approved Integrations table: click the bin icon next to it. Revoking is instant and breaks nothing except that token.
One-click install
These clients support installing an MCP server from a link. Each button opens the
client with canvas-api-mcp pre-filled — replace your-token-here in the client's
add-server dialog with your own token from the prerequisites above before saving.
VS Code's insiders build uses the same redirect under vscode-insiders:// instead —
build the link yourself from the manual VS Code config if
you're on Insiders. LM Studio's deeplink requires LM Studio 0.3.17 or later.
Claude Code, Claude Desktop, Windsurf, and Zed have no install-from-link mechanism for arbitrary servers — configure them by hand in Manual configuration below.
Manual configuration
Add canvas-api-mcp to your MCP client's config, using uvx so nothing needs a
separate install step. Fill in your own CANVAS_BASE_URL and the token you minted
above.
Easiest via the CLI, which writes the config for you:
claude mcp add canvas-api-mcp --scope project \
--env CANVAS_BASE_URL=https://canvas.nus.edu.sg \
--env CANVAS_TOKEN=your-token-here \
-- uvx canvas-api-mcpSwap --scope project for --scope user to register the server globally, or omit
--scope entirely for the local/private default.
Or edit the config directly — project-shared config lives in <project>/.mcp.json;
user and local (private, per-project) config both live inside ~/.claude.json:
{
"mcpServers": {
"canvas-api-mcp": {
"command": "uvx",
"args": ["canvas-api-mcp"],
"env": {
"CANVAS_BASE_URL": "https://canvas.nus.edu.sg",
"CANVAS_TOKEN": "your-token-here"
}
}
}
}No deeplink/URL-install scheme is documented for Claude Code.
Published on PyPI
canvas-api-mcp is published on PyPI.
Every config on this page runs uvx canvas-api-mcp directly — uvx fetches the
package from PyPI and runs it with no separate install step.
Install from source (development only)
Testing an unreleased change on main? Point uvx at the repo instead of PyPI:
uvx --from git+https://github.com/JohannsenLum/canvas-api-mcp canvas-api-mcp. This
is a development-only path — regular installs above should always use the plain
uvx canvas-api-mcp form.
Verify the connection
Restart your MCP client so it picks up the new server, then ask it to call whoami —
or, if your client exposes a tool list in its UI, check that canvas-api-mcp's 18
tools appear there. A correct whoami response names the Canvas account the token
belongs to and that account's role in each course. You can also ask something like
"what's due this week on Canvas?" — if it calls whats_due and returns real
deadlines, the token and base URL are both correct.
Troubleshooting
"Invalid token" / 401 errors. The token is wrong, expired, or was revoked. Mint
a new one at Account → Settings → Approved Integrations → "+ New access token"
and update your client's config with it.
It worked for weeks and then stopped. This is almost always the expiry, not a
break. Student-role Canvas tokens are capped at 120 days by Instructure and often
lower by the institution (NUS allows 90), so a working setup dies on a schedule you
agreed to months earlier and have since forgotten. The symptom is every tool
returning 401 at once, having previously been fine. Check the token's expiry date
in Approved Integrations before debugging anything else: a config that has not
changed did not break itself.
My institution doesn't show "Approved Integrations". Student personal-access-token generation isn't guaranteed everywhere — it varies by Canvas deployment and by institution policy. Ask your institution's IT whether student token generation is enabled; if it's disabled, this server cannot be used against that Canvas instance until it is.
Python version too old. The server requires Python 3.11+. uvx normally
resolves an appropriate interpreter on its own, but if it fails, check your installed
Python version and upgrade if it's below 3.11.
Server doesn't appear in the client. Confirm you fully restarted the client (for
Claude Desktop, quit with Cmd+Q or the tray icon's Exit — closing the window is not
enough) and that the config file is valid JSON in the exact shape shown above for
your client — a missing "type": "stdio" on VS Code, a command that isn't a plain
string on Zed, or a stray trailing comma anywhere will keep the server from loading. If the
client logs a JSON parse error, fix the file and restart again. If it loads but calls
fail, the server's own startup diagnostics name the missing or malformed environment
variable.
Configuration reference
| Variable | Required | Purpose |
|---|---|---|
CANVAS_BASE_URL | yes | Your institution's Canvas root URL, e.g. https://canvas.nus.edu.sg. No trailing slash, no /api/v1. |
CANVAS_TOKEN | yes | The personal access token from the prerequisites above. |
CANVAS_MAX_PAGES | no | Pagination cap for list responses. Default 10. |
CANVAS_BASE_URL must use https:// — access tokens are password-equivalent and must
not travel over plain http.
Regenerating the endpoint catalog
canvas-api-mcp ships with a bundled catalog of 1,116 Canvas API endpoints, which is
what the gateway tools search_canvas_api and canvas_request search and call
against. Different institutions run different Canvas versions with different
endpoints enabled, so the bundled catalog is a sensible default, not a guarantee of
what your own instance exposes. Most users never need to touch this.
If you want the catalog to match your institution's Canvas exactly, regenerate it from that instance's own Swagger spec:
canvas-api-mcp-build-catalog https://canvas.nus.edu.sgThis works from a plain pip/uvx install — no source checkout required. It fetches
{base_url}/doc/api/api-docs.json and writes the result to
~/.cache/canvas-api-mcp/catalog.json by default. Pass -o/--output to write
somewhere else instead.
canvas-api-mcp resolves which catalog to load in this order:
- An explicit path passed in code.
- The
CANVAS_CATALOG_PATHenvironment variable, if set. ~/.cache/canvas-api-mcp/catalog.json, if it exists.- The bundled catalog shipped with the package.
Regenerating with the default output path is enough on its own — the server picks it
up from the cache directory on its next start, no config changes required. Set
CANVAS_CATALOG_PATH (alongside CANVAS_BASE_URL and CANVAS_TOKEN in your client
config) only if you want the catalog to live somewhere other than the cache directory.
Where your token goes
Your token is supplied through your MCP client's own env block and stays in that
client's local config file, on your machine. It is read by the local canvas-api-mcp
process and sent as a bearer token on requests made directly to your own
CANVAS_BASE_URL — nowhere else. No hosted service, and no third party, ever sees it.
That also means nobody else can rotate or revoke it for you: if it leaks, you're the
one who deletes it from Canvas.