Skip to main content
Glama

Canvas LMS integration for Poke

License: MIT Python Protocol: MCP Security

Connect your Canvas LMS account to Poke by The Interaction Company so you can ask Poke about your classes in plain language:

"What's due this week?" · "Did my CS101 grade change?" · "Read me the syllabus page" · "Any new announcements?"

It's a small FastMCP server that wraps the Canvas REST API and speaks the Model Context Protocol (MCP) Poke connects to. Once deployed, Poke discovers the tools automatically and uses them whenever a question is about your coursework.

All data is read live on every request, so answers always reflect the current state of Canvas — new assignments, changed grades, fresh announcements, updated due dates. There is nothing to re-sync.


⚡ 1-click setup

Hosted — no terminal. Click, set 2 fields, deploy:

Deploy to Render   Deploy to Heroku

On the deploy screen set CANVAS_BASE_URL + CANVAS_API_TOKEN. Then open your new service URL in a browser — the page shows your live MCP link and a one-tap-copy npx poke@latest mcp add … command already filled in with your URL. Paste it and Poke is connected. (Set the optional POKE_API_KEY too and the server texts you a "Canvas is live" confirmation on boot.)

Local — one paste:

curl -fsSL https://raw.githubusercontent.com/jackulau/PokeCanvas/main/bootstrap.sh | bash

This bootstrap.sh installs everything, asks for your Canvas URL + token once, opens a public tunnel, and registers it with Poke for you.

Other hosts (Railway, Fly, Docker, VPS) → HOSTING.md. Step-by-step detail below.


Related MCP server: Canvas LMS MCP Server

How it's hosted — two models

This is built as a multi-tenant server, so there are two ways to run it:

  • Shared instance (least setup): one deployment serves many people. Each user adds the shared /mcp URL in Poke and passes their own Canvas credentials as the integration key — https://canvas.yourschool.edu::YOUR_CANVAS_TOKEN. No per-user hosting, nothing to deploy. The server is hardened for untrusted callers: SSRF protection on the Canvas URL, per-user rate limiting (X-Poke-User-Id), and it never logs or stores tokens. See SECURITY.md.

  • Self-host (most private): deploy your own (the 1-click above), set CANVAS_BASE_URL + CANVAS_API_TOKEN, connect with no key. Your token never leaves infrastructure you control.

Not sure which? Self-host — it's one click and the token stays yours.


What Poke can see

Every resource you asked for, each as an MCP tool Poke calls on demand:

Area

Tools

Courses

list_courses (with current grade + term), get_profile

Assignments

list_assignments (incl. your score / submission status / late / missing)

Files

list_files

Pages

list_pages, get_page (full content)

Modules

list_modules (with the items inside each)

Announcements

list_announcements (one course, or all at once)

Discussions

list_discussions

Quizzes

list_quizzes

Calendar

list_calendar_events, list_upcoming_events

To-dos / changes

list_todos, get_recent_activity (the live "what changed" feed)

Read-only by design — it never submits, posts, or deletes anything in Canvas.


Setup

Three steps. Fastest path with no signup: ./setup.sh — it installs deps, asks for your Canvas URL + token once, opens a public tunnel, and registers it with Poke for you. Prefer real 24/7 hosting? Full per-host instructions live in HOSTING.md.

1. Get your Canvas access token

In Canvas: Account → Settings → Approved Integrations → "+ New Access Token". Copy it (shown once). Note your Canvas URL — where you log in, e.g. https://canvas.university.edu.

2. Deploy the server — pick one

One-click hosted:

Deploy to Render   Deploy to Heroku

Or local, no signup:

git clone https://github.com/jackulau/PokeCanvas && cd PokeCanvas
./setup.sh

Set CANVAS_BASE_URL + CANVAS_API_TOKEN on whichever host you pick. Every option ends with a URL like https://<host>/mcpnote the /mcp, no trailing slash. Render / Railway / Fly / Heroku / Docker / VPS / tunnel details → HOSTING.md.

Render's free tier sleeps after ~15 min idle (first request after a nap ~50s). Railway/Fly/Heroku or your own Docker host avoid cold starts.

3. Connect it to Poke

Because the credentials live on your server, Poke needs no API key — just the URL.

  • One command: npx poke@latest mcp add https://<host>/mcp -n "Canvas"

  • Or web UI: poke.com/settings/connectionsNew integration → Name Canvas, URL https://<host>/mcp, leave the API key blank → Create.

  • Or shareable recipe (Poke sets it up for any user from one link): recipe/recipe.md.

Then message Poke "What courses am I taking?"


"Dynamically update if anything changes"

There's no stale cache to worry about: every tool call hits Canvas in real time. Three things make change-tracking explicit:

  • get_recent_activity — Canvas's activity stream: new announcements, grade changes, submission comments, discussion replies.

  • list_todos / list_upcoming_events — what needs action and what's due, soonest first.

  • list_assignments returns your live submission state (graded? late? missing? score?).

Want Poke to proactively ping you when something changes (not just when you ask)? Add a scheduled automation — the recipe in recipe/ includes a ready-to-use prompt for it ("every morning, check get_recent_activity and text me anything new").


Auth modes

Mode

When

How

Env vars (default)

You run your own server

Set CANVAS_BASE_URL + CANVAS_API_TOKEN on the host. Connect to Poke with no key.

Bearer token

One server, you pass the token from Poke

Put your token in Poke's API-key field. Base URL still comes from CANVAS_BASE_URL (or send an X-Canvas-Base-Url header).

Composite bearer

A shared server for many schools (e.g. a recipe)

Poke API key = https://canvas.yourschool.edu::YOUR_TOKEN. The server splits it per user.

Precedence: a token in the request beats the env token; the request base URL (composite or header) beats CANVAS_BASE_URL.


Local development

python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt

# Run it
export CANVAS_BASE_URL=https://canvas.youruni.edu
export CANVAS_API_TOKEN=your_token
python src/server.py            # serves http://localhost:8000/mcp

# Verify (no Canvas account needed — uses mocks + a live protocol check)
pytest -q                       # unit tests
python scripts/smoke_tools_list.py   # all tools registered  -> TOOLS_OK
ruff check src tests scripts    # lint

To test the live transport the way Poke sees it:

PORT=8765 python src/server.py &
python scripts/live_http_test.py http://127.0.0.1:8765/mcp   # -> LIVE_OK

Troubleshooting

Symptom

Fix

First request hangs ~50s

Render free-tier cold start; it's awake now. Use a paid/always-on host to avoid.

401 ... access token

Token wrong/expired, or CANVAS_API_TOKEN not set on the host. Regenerate in Canvas.

401 ... base URL

CANVAS_BASE_URL not set, or wrong (must be your login URL, e.g. https://canvas.uni.edu).

Poke "can't reach the tool"

Confirm the URL ends in /mcp (no trailing slash). Try clearhistory in Poke, then re-test.

Empty course list

The token's user may have no active enrollments; try "list all my courses including past ones".


How it works

Poke  ──(MCP over HTTPS, streamable-http at /mcp)──►  this server  ──(REST + Bearer)──►  Canvas LMS API
  • src/server.py — FastMCP app (transport="http", stateless_http=True), tool + route registration, landing page (/), health (/health), optional boot ping.

  • src/tools.py — the 14 @mcp.tool definitions; rate-limit, build a client from the request, call the data layer, return clean errors.

  • src/canvas_api.py — one function per resource; maps to Canvas endpoints and trims responses to what matters.

  • src/canvas_client.py — async HTTP, credential resolution, and transparent Canvas Link-header pagination.

  • src/security.py — SSRF guard for the caller-supplied Canvas URL (multi-tenant).

  • src/ratelimit.py — per-user sliding-window rate limiter.

  • src/landing.py — the self-configuring connect page served at /.

See recipe/recipe.md for the Poke recipe and onboarding copy.


Security

Read-only, stateless, tokens never stored or logged, HTTPS-only, with SSRF protection and per-user rate limiting for shared deployments. Full threat model and the self-host-vs-shared tradeoff: SECURITY.md. Report vulnerabilities via a private GitHub security advisory.

Contributing

Issues and PRs welcome.

git clone https://github.com/jackulau/PokeCanvas && cd PokeCanvas
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
pytest -q && ruff check src tests scripts      # keep both green

Please add a test for any new tool or behavior and keep ruff clean.

License

MIT © 2026 jacklau

Related MCP Connectors

Related MCP Servers