canvas-mcp-server
canvas-mcp-server
MCP-Server für die Canvas LMS REST-API. Gibt einem LLM Lesezugriff auf deine Kurse, Aufgaben, Noten, Abgaben, Ankündigungen, Diskussionen, Module, Seiten und Dateien.
20 Tools, alle schreibgeschützt.
Voraussetzungen
Node.js 18+
Ein Canvas-Konto an einer beliebigen Einrichtung
Ein Zugriffstoken aus Konto → Einstellungen → Neues Zugriffstoken in deiner Canvas-Weboberfläche
Installation
npm install
npm run buildKonfiguration
Canvas hat keinen gemeinsamen API-Host – jede Einrichtung betreibt ihren eigenen. Beide unten aufgeführten Variablen sind erforderlich.
{
"mcpServers": {
"canvas": {
"command": "node",
"args": ["/absolute/path/to/canvas-mcp-server/dist/index.js"],
"env": {
"CANVAS_BASE_URL": "https://bcourses.berkeley.edu",
"CANVAS_ACCESS_TOKEN": "your-token-here"
}
}
}
}Variable | Erforderlich | Standard | Zweck |
| ja | — | Der Canvas-Host deiner Einrichtung, inklusive Schema, ohne abschließenden Pfad |
| ja | — | Konto → Einstellungen → Neues Zugriffstoken |
| nein |
| Zeitüberschreitung pro Anfrage |
| nein |
|
|
| nein |
| HTTP-Transport-Bindungsadresse |
| bei gehostet | — | Stellt den Endpunkt unter |
| nein | localhost + claude.ai | Durch Kommas getrennte Origin-Whitelist |
Untersuche die Tools interaktiv:
CANVAS_BASE_URL=https://your.canvas CANVAS_ACCESS_TOKEN=your-token npm run inspectBereitstellung (für Claude Mobile / claude.ai-Connectors)
Claude verbindet sich mit benutzerdefinierten Connectors aus der Cloud von Anthropic, nicht von deinem Gerät. Daher müssen Mobile und claude.ai dies über öffentliches HTTPS erreichen können. Claude Code und Claude Desktop tun das nicht – verwende dort stattdessen stdio.
1. Pfad-Geheimnis generieren
openssl rand -hex 32Der Server weigert sich, auf einer Nicht-Loopback-Schnittstelle ohne gesetztes MCP_PATH_SECRET zu starten, da ein öffentlicher Endpunkt, der dein Canvas-Token enthält, ein offener Proxy für dein Konto ist. Mit gesetztem Geheimnis wechselt der Endpunkt zu /mcp/<secret> und jeder andere Pfad gibt 404 zurück – auch bei falschem Geheimnis. So verrät das Abtasten des Hosts nicht, dass dort ein MCP-Server lebt.
2. Bereitstellen
Die enthaltenen Dockerfile und railway.json funktionieren unverändert auf Railway, Render oder Fly. Das Image setzt TRANSPORT=http und HOST=0.0.0.0 und läuft als Nicht-Root-Benutzer. Setze drei Variablen im Dashboard der Plattform:
Variable | Wert |
| der Canvas-Host deiner Einrichtung |
| dein Token |
| der Wert aus Schritt 1 |
PORT wird von der Plattform injiziert. /healthz ist ein nicht authentifizierter Liveness-Healthcheck.
3. Überprüfen
curl -s https://your-app.up.railway.app/healthz4. Connector hinzufügen
Auf claude.ai in einem Browser – Connectors können nicht aus der Mobile-App hinzugefügt werden:
Anpassen → Connectors → Benutzerdefinierten Connector hinzufügen
URL:
https://your-app.up.railway.app/mcp/<secret>Öffne auf deinem Telefon einen Chat und aktiviere ihn unter + → Connectors
Behandle diese URL wie ein Passwort. Wenn sie durchsickert, rotiere MCP_PATH_SECRET und füge den Connector erneut hinzu.
Tools
Kurse — canvas_list_courses, canvas_get_course, canvas_get_grades, canvas_list_enrollments, canvas_get_profile
Aufgaben — canvas_list_assignments, canvas_get_assignment, canvas_get_submission, canvas_list_quizzes
Planer — canvas_list_planner_items, canvas_list_upcoming, canvas_list_calendar_events
Ankündigungen und Diskussionen — canvas_list_announcements, canvas_list_discussions, canvas_get_discussion
Kursinhalte — canvas_list_modules, canvas_list_module_items, canvas_list_pages, canvas_get_page, canvas_list_files
Jedes Lesetool akzeptiert response_format: "markdown" | "json". Markdown ist die Standardeinstellung und für das Lesen durch ein LLM optimiert; JSON ist die vollständige strukturierte Nutzlast. structuredContent ist unabhängig vom Format immer gefüllt.
Beispiele
„Was ist diese Woche fällig?"
→ canvas_list_planner_items mit end_date eine Woche voraus. Deckt alle Kurse in einem Aufruf ab und meldet den Abgabestatus. Es beginnt standardmäßig ab heute. Für „Was habe ich verpasst?" übergebe ein explizites früheres start_date.
„Was sind meine Noten?"
→ canvas_get_grades. Ein Aufruf, alle aktiven Kurse, aktueller Punktestand und Notenbuchstabe.
„Was haben meine Professoren diese Woche angekündigt?"
→ canvas_list_courses für IDs, dann canvas_list_announcements mit allen auf einmal.
„Was muss ich eigentlich für Projekt 2 tun?"
→ canvas_list_assignments mit search_term="project 2", um die ID zu erhalten, dann canvas_get_assignment für die vollständigen Anweisungen.
Designhinweise
Von Natur aus schreibgeschützt. Jedes Tool trägt readOnlyHint: true und destructiveHint: false, und der Client hat keinen Schreibpfad. Canvas-Tokens tragen die volle Autorität deines Kontos – sie können Aufgaben einreichen, in Diskussionen posten und Profileinstellungen ändern – daher weigert sich der Server bewusst, all das offenzulegen. Ein Test stellt dies sicher: Wenn jemals ein Schreib-Tool hinzugefügt wird, schlägt die Testsuite fehl.
Die Basis-URL ist erforderlich, nicht standardmäßig gesetzt. Im Gegensatz zu Single-Tenant-APIs betreibt Canvas eine Instanz pro Einrichtung. Es gibt keinen sinnvollen Standard, und ein Token, das von der Canvas einer Schule ausgestellt wurde, ist bei einer anderen bedeutungslos. Daher schlägt der Server beim Start fehl, anstatt dich später mit 401-Fehlern in die Irre zu führen.
Paginierung lebt in einem Header. Canvas meldet „Gibt es eine nächste Seite?" in einem RFC-5988-Link-Header und gibt niemals eine Gesamtzahl zurück. Diese URLs sind als undurchsichtig dokumentiert, daher wird has_more aus dem Header gelesen, während page/per_page die aufruferseitigen Steuerelemente bleiben – ein Agent erhält ein einfaches next_page zum Folgen, anstatt einen Cursor zu verwalten.
IDs werden als Zeichenketten angefordert. Canvas-IDs sind 64-Bit-Ganzzahlen, die JavaScript nicht exakt darstellen kann. Der Client sendet Accept: application/json+canvas-string-ids, was Canvas respektiert, indem es jede ID als Zeichenkette zurückgibt. So überstehen IDs eine JSON-Roundtrip unversehrt.
HTML wird abgeflacht, bevor es das Modell erreicht. Aufgabenbeschreibungen, Ankündigungen, Diskussionsbeiträge und Seiten sind alle als HTML gespeichert. Wenn man das unverändert durchreicht, verbrennt es enorm viel Kontext für Markup. Daher werden Tags zu Zeilenumbrüchen, Entitäten werden dekodiert und lange Texte werden mit der html_url für die vollständige Version auszugsweise dargestellt.
include[] wird nicht offengelegt. Canvas hat zwei Dutzend Include-Optionen, die sich zwischen den Listen- und Einzelkurs-Endpunkten unterscheiden, und die meisten steuern Felder, die ein Agent nicht benötigt. Jedes Tool fordert an, was es braucht, und zeigt nur die Umschalter, die ändern, was ein Benutzer sehen würde – include_syllabus, include_grades, include_submission.
Kurs-IDs werden in Kontextcodes normalisiert. Einige Canvas-Endpunkte adressieren Kurse als course_1234 statt 1234. Beide Formen werden überall akzeptiert und umgewandelt, sodass der Agent sich nie merken muss, welcher Endpunkt welche Form erwartet.
Fehler führen zu nächsten Aktionen. Ein 404 nennt das Tool, das gültige IDs für diese Ressource erzeugt. Ein 403 unterscheidet ein Berechtigungsproblem von einem erschöpften Ratenlimit, das Canvas verwirrenderweise unter demselben Status zurückgibt. Ein 401 weist darauf hin, dass ein Token von der Canvas einer Schule bei einer anderen nicht funktioniert.
Zwei Canvas-Eigenheiten werden behandelt, nicht weitergegeben. Die Note, die ein Kurs unter enrollments[].computed_current_score meldet, ist dieselbe Zahl, die die Enrollments-API grades.current_score nennt; beide werden gelesen. Und das submissions-Feld eines Planer-Elements ist der boolesche Wert false – kein Objekt – wenn nichts einreichbar ist, was vor dem Lesen geprüft wird.
Einschränkungen
Ankündigungen können nicht global aufgelistet werden: Canvas erfordert mindestens eine Kurs-ID, daher muss zuerst
canvas_list_coursesausgeführt werden.canvas_list_discussionswendet seinenscope-Filter nach der Paginierung an, sodass eine gefilterte Seite kürzer alsper_pagezurückkommen kann, ohne das Ende der Ergebnisse zu sein.Canvas lässt Modulelemente aus der Listenantwort für Module weg, die es als groß betrachtet;
canvas_list_module_itemsruft sie ab.Seiten werden über URL-Slug (
week-1-reading) adressiert, nicht über den Titel.canvas_list_pagesgibt den Slug in seinemurl-Feld zurück.Der Kalender-Endpunkt akzeptiert höchstens 10 Kurse und ignoriert den Rest stillschweigend;
canvas_list_calendar_eventsmeldet, wenn er kürzt.Noten spiegeln nur das wider, was ein Dozent veröffentlicht hat, und werden für Kurse, die so konfiguriert sind, dass sie Endnoten verbergen, vollständig weggelassen.
Projektstruktur
src/
├── index.ts # entry point, transport selection
├── constants.ts # enum values, limits, character limit
├── types.ts # interfaces for every Canvas entity
├── services/
│ └── canvas-client.ts # fetch wrapper, auth, Link pagination, error → guidance mapping
├── schemas/
│ ├── inputs.ts # Zod input schemas
│ └── outputs.ts # structuredContent schemas
├── formatters/
│ ├── response.ts # pagination, truncation, HTML flattening, format dispatch
│ └── entities.ts # per-entity markdown rendering
└── tools/
├── courses.ts
├── assignments.ts
├── planner.ts
├── announcements.ts
└── content.tsTests
npm run build
npm test # 43 checks: MCP handshake, tools, pagination, formatting, errors (mocked API)
npm run test:http # 19 checks: config validation, path-secret gating, method handling, originsBeide Test-Suiten laufen gegen einen lokalen Mock, sodass kein Token oder Netzwerkzugriff erforderlich ist.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Read-only MCP server for ClassQuill, a tutoring-business-management platform.
Read-only MCP server for Muovi, Argentina's trust-first local services marketplace (6 tools).
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/RyK57/canvas-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server