canvas-mcp-server
canvas-mcp-server
MCP-сервер для REST API Canvas LMS. Даёт LLM доступ на чтение к вашим курсам, заданиям, оценкам, сдачам, объявлениям, обсуждениям, модулям, страницам и файлам.
20 инструментов, все только для чтения.
Требования
Node.js 18+
Учётная запись Canvas в любом учебном заведении
Токен доступа из Account → Settings → New Access Token в веб-интерфейсе Canvas
Установка
npm install
npm run buildНастройка
У Canvas нет общего API-хоста — каждое учебное заведение запускает свой. Обе переменные ниже обязательны.
{
"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"
}
}
}
}Переменная | Обязательна | По умолчанию | Назначение |
| да | — | Хост Canvas вашего учебного заведения, включая схему, без завершающего пути |
| да | — | Account → Settings → New Access Token |
| нет |
| Таймаут на запрос |
| нет |
|
|
| нет |
| Адрес привязки HTTP-транспорта |
| при хостинге | — | Обслуживает конечную точку на |
| нет | localhost + claude.ai | Разрешённые источники через запятую |
Просмотрите инструменты в интерактивном режиме:
CANVAS_BASE_URL=https://your.canvas CANVAS_ACCESS_TOKEN=your-token npm run inspectРазвёртывание (для мобильных Claude / коннекторов claude.ai)
Claude подключается к пользовательским коннекторам из облака Anthropic, а не с вашего устройства, поэтому мобильным и claude.ai нужен доступ по публичному HTTPS. Claude Code и Claude Desktop — нет; используйте там stdio.
1. Сгенерируйте секрет пути
openssl rand -hex 32Сервер отказывается запускаться на не-loopback интерфейсе без установленного MCP_PATH_SECRET, потому что публичная конечная точка, содержащая ваш токен Canvas, является открытым прокси к вашей учётной записи. С установленным секретом конечная точка перемещается на /mcp/<secret>, и любой другой путь возвращает 404 — включая неверный секрет, так что сканирование хоста не раскрывает, что там живёт MCP-сервер.
2. Разверните
Включённые Dockerfile и railway.json работают как есть на Railway, Render или Fly. Образ устанавливает TRANSPORT=http и HOST=0.0.0.0 и запускается от непривилегированного пользователя. Установите три переменные в панели управления платформы:
Переменная | Значение |
| хост Canvas вашего учебного заведения |
| ваш токен |
| значение из шага 1 |
PORT внедряется платформой. /healthz — неаутентифицированный зонд живости.
3. Проверьте
curl -s https://your-app.up.railway.app/healthz4. Добавьте коннектор
На claude.ai в браузере — коннекторы нельзя добавить из мобильного приложения:
Customize → Connectors → Add custom connector
URL:
https://your-app.up.railway.app/mcp/<secret>На телефоне откройте чат и включите его в разделе + → Connectors
Относитесь к этому URL как к паролю. Если он утёк, смените MCP_PATH_SECRET и добавьте коннектор заново.
Инструменты
Курсы — canvas_list_courses, canvas_get_course, canvas_get_grades, canvas_list_enrollments, canvas_get_profile
Задания — canvas_list_assignments, canvas_get_assignment, canvas_get_submission, canvas_list_quizzes
Планировщик — canvas_list_planner_items, canvas_list_upcoming, canvas_list_calendar_events
Объявления и обсуждения — canvas_list_announcements, canvas_list_discussions, canvas_get_discussion
Содержимое курса — canvas_list_modules, canvas_list_module_items, canvas_list_pages, canvas_get_page, canvas_list_files
Каждый инструмент чтения принимает response_format: "markdown" | "json". Markdown используется по умолчанию и оптимизирован для чтения LLM; JSON — это полная структурированная полезная нагрузка. structuredContent всегда заполняется независимо от формата.
Примеры
«Что нужно сдать на этой неделе?»
→ canvas_list_planner_items с end_date на неделю вперёд. Охватывает все курсы одним вызовом и сообщает состояние сдачи. По умолчанию он начинается с сегодняшнего дня, поэтому для «что у меня просрочено» передайте явный более ранний start_date.
«Какие у меня оценки?»
→ canvas_get_grades. Один вызов, все активные курсы, текущий балл и буквенная оценка.
«Что объявили мои преподаватели на этой неделе?»
→ canvas_list_courses для идентификаторов, затем canvas_list_announcements со всеми ними сразу.
«Что мне на самом деле нужно сделать для проекта 2?»
→ canvas_list_assignments с search_term="project 2" для получения идентификатора, затем canvas_get_assignment для полных инструкций.
Замечания по дизайну
Только для чтения по построению. Каждый инструмент несёт readOnlyHint: true и destructiveHint: false, и у клиента нет открытого пути записи. Токены Canvas несут полные полномочия вашей учётной записи — они могут отправлять задания, публиковать сообщения в обсуждениях и изменять настройки профиля — поэтому сервер намеренно отказывается раскрывать что-либо из этого. Тест проверяет это: если когда-либо будет добавлен инструмент записи, набор тестов завершится ошибкой.
Базовый URL обязателен, а не задан по умолчанию. В отличие от однопользовательских API, Canvas запускает один экземпляр на учебное заведение. Разумного значения по умолчанию нет, и токен, выданный Canvas одной школы, бессмысленен в другой, поэтому сервер завершается с ошибкой при запуске, а не вводит вас в заблуждение ошибками 401 позже.
Пагинация живёт в заголовке. Canvas сообщает «есть ли следующая страница» в заголовке Link RFC 5988 и никогда не возвращает общее количество. Эти URL документированы как непрозрачные, поэтому has_more читается из заголовка, а page/per_page остаются элементами управления для вызывающей стороны — агент получает простой next_page для перехода вместо курсора для навигации.
Идентификаторы запрашиваются как строки. Идентификаторы Canvas — 64-битные целые числа, которые JavaScript не может представить точно. Клиент отправляет Accept: application/json+canvas-string-ids, и Canvas выполняет это, возвращая каждый идентификатор строкой, поэтому идентификаторы переживают JSON-кругосветку без изменений.
HTML уплощается до того, как достигает модели. Описания заданий, объявления, сообщения обсуждений и страницы хранятся в HTML. Передача этого дословно сжигает огромный контекст на разметке, поэтому теги превращаются в разрывы строк, сущности декодируются, а длинные тела сокращаются с сохранением html_url для полной версии.
include[] не раскрывается. У Canvas два десятка опций include, они различаются между конечными точками списка и отдельного курса, и большинство управляют полями, которые агенту не нужны. Каждый инструмент запрашивает то, что ему нужно, и показывает только переключатели, меняющие то, что увидит пользователь — include_syllabus, include_grades, include_submission.
Идентификаторы курсов нормализуются в коды контекста. Некоторые конечные точки Canvas обращаются к курсам как course_1234, а не 1234. Обе формы принимаются везде и преобразуются, поэтому агенту не нужно запоминать, какая конечная точка какую хочет.
Ошибки приводят к следующим действиям. Ошибка 404 называет инструмент, который выдаёт допустимые идентификаторы для этого ресурса. Ошибка 403 отличает проблему с правами доступа от исчерпанного лимита запросов, который Canvas сбивающе возвращает под тем же статусом. Ошибка 401 указывает, что токен из Canvas одной школы не будет работать в другой.
Две особенности Canvas обрабатываются, а не передаются дальше. Оценка, которую курс сообщает в enrollments[].computed_current_score, — это то же число, которое API Enrollments называет grades.current_score; читаются оба. А поле submissions элемента планировщика — это логическое false — не объект — когда нечего сдавать, что проверяется перед чтением.
Предостережения
Объявления нельзя получить глобально: Canvas требует хотя бы один идентификатор курса, поэтому сначала должен выполняться
canvas_list_courses.canvas_list_discussionsприменяет свой фильтрscopeпосле пагинации, поэтому отфильтрованная страница может вернуться короче, чемper_page, не будучи концом результатов.Canvas опускает элементы модулей из ответа списка для модулей, которые считает большими;
canvas_list_module_itemsполучает их.Страницы адресуются по url-слагу (
week-1-reading), а не по заголовку.canvas_list_pagesвозвращает слаг в своём полеurl.Конечная точка календаря принимает не более 10 курсов и молча игнорирует остальные;
canvas_list_calendar_eventsсообщает, когда усекает.Оценки отражают только то, что опубликовал преподаватель, и полностью опускаются для курсов, настроенных скрывать итоговые оценки.
Структура проекта
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.tsТесты
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, originsОба набора тестов запускаются против локального макета, поэтому не нужны ни токен, ни доступ к сети.
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