Skip to main content
Glama
mcp-canvas-utem
by k0ngan

mcp-canvas-utem

Servidor MCP de solo lectura para Canvas LMS que, en la misma llamada con la que lee, deja las notas correspondientes en un vault de Obsidian ya etiquetadas. No hay un segundo paso ni una herramienta aparte que haya que acordarse de invocar: leer Canvas es sincronizar el vault.

Sin dependencias. Node.js 18 o superior.

Qué hace distinto

El etiquetado y el frontmatter los decide el código, no el modelo. Toda nota sincronizada sale con la misma forma:

---
tags:
  - segundo-semestre     # campaña, del dígito del semestre
  - canvas               # raíz, en toda nota sincronizada
  - 2026-2               # semestre detectado en el nombre o el código del curso
  - canvas/archivo       # arquetipo: curso|archivo|tarea|pagina|modulo|anuncio|discusion
tipo: archivo
course_id: 31973
file_id: 1218706
filename: GUIA.pdf
content_type: application/pdf
size: 473737
updated_at: "2026-08-11T19:00:42Z"
download_url: "https://utem.instructure.com/files/1218706/download?download_frd=1"
semestre: segundo semestre
---

Markdown y YAML planos: nada de Dataview ni Templater, así que las notas se leen igual en cualquier instalación de Obsidian.

Related MCP server: canvas-mcp-server

Instalación

npx -y github:k0ngan/mcp_canvas

O desde el repo clonado:

node bin/mcp-canvas-utem.mjs

Registro en Claude Code

Un .mcp.json en la raíz del proyecto, sin secretos dentro:

{
  "mcpServers": {
    "canvas": {
      "command": "npx",
      "args": ["-y", "github:k0ngan/mcp_canvas"],
      "env": { "CANVAS_VAULT_DIR": "C:\\ruta\\a\\tu\\vault" }
    }
  }
}

npx guarda en caché la versión que descargó. Para forzar una nueva, apunta al commit: github:k0ngan/mcp_canvas#<sha>.

Registro en Codex

[mcp_servers.canvas]
command = "node"
args = ["bin/mcp-canvas-utem.mjs"]
cwd = "C:\\ruta\\al\\repo\\mcp_canvas"
startup_timeout_sec = 20
tool_timeout_sec = 300

El servidor usa la cookie de sesión del navegador, no un token de API. Inicia sesión en Canvas, copia el valor de la cookie canvas_session del dominio de tu institución y guárdalo fuera del repositorio, en %LOCALAPPDATA%\canvas-utem-mcp\canvas_session:

canvas_session=VALOR

También acepta el valor pelado o un header Cookie: completo. Nunca lo pegues en la configuración del MCP ni lo subas a ningún repo. Cuando Canvas responda 401 o 403, vuelve a iniciar sesión y reemplaza el contenido de ese archivo.

Para otra ruta, CANVAS_COOKIE_FILE. Para un proceso efímero, CANVAS_COOKIE_HEADER.

Variables de entorno

Variable

Por defecto

Para qué

CANVAS_BASE_URL

https://utem.instructure.com

instancia de Canvas; también es la allowlist de origen

CANVAS_COOKIE_FILE

%LOCALAPPDATA%\canvas-utem-mcp\canvas_session

archivo con la cookie de sesión

CANVAS_COOKIE_HEADER

—

cookie por entorno, tiene prioridad sobre el archivo

CANVAS_VAULT_DIR

—

raíz del vault. Sin esto no se escribe nada, solo se lee

CANVAS_SUBDIR

Canvas

carpeta de Canvas dentro del vault

CANVAS_TERM_FOLDER

1

agrupa los cursos en Segundo semestre 2026 según el semestre

CANVAS_OUTPUT_DIR

<vault>/../output/pdf

destino de canvas_download_pdf y de las exportaciones

CANVAS_TAGS_FILE

<vault>/<subdir>/vault-tags.json

mapa course_code → tag temático

CANVAS_VAULT_WRITE

1

interruptor general de la escritura

CANVAS_VAULT_DRY_RUN

0

simula siempre, sin tocar el disco

CANVAS_EOL

el del sistema

fin de línea de las notas nuevas

CANVAS_TIMEOUT_SEC

30

timeout de las llamadas a la API

CANVAS_PAGE_SIZE

100

tamaño de página de la API

El token de API no se soporta a propósito: el modo cookie es el que se usa y evita tener otro secreto guardado en disco. CANVAS_TOKEN se ignora.

Tags temáticos

vault-tags.json mapea el código de la asignatura a un tag. Sin mapeo no se inventa ninguno:

{
  "FISC8040": "electromagnetismo",
  "INFB6065": "bases-de-datos",
  "MATC8050": "metodos-numericos"
}

Herramientas

Lectura, todas con write-through al vault:

Herramienta

Qué deja en el vault

canvas_test_connection

nada; es la única que no escribe

canvas_list_courses

una nota de curso por curso activo y el índice del semestre

canvas_list_active_tasks

las notas de las tareas pendientes

canvas_list_course_assignments

todas las notas de tareas del curso

canvas_course_inventory

la nota de curso con los conteos por recurso

canvas_course_updates

anuncios, archivos y módulos

canvas_download_pdf

el PDF en la carpeta de salida y su nota de archivo

Sincronización y exportación:

Herramienta

Entrada

canvas_sync_course

course_id; opcional download_files, include_announcements, include_discussions

canvas_sync_all_courses

term (por defecto el más reciente), all_terms, download_files

canvas_download_course_files

course_id, force

canvas_export_course_sources

course_id: instrucciones, páginas, módulos, enlaces y adjuntos como JSON

canvas_vault_status

sin argumentos: dónde escribe y qué cursos detecta

Todas aceptan dry_run: true, que devuelve el plan completo sin escribir. Cada respuesta trae un bloque vault con el recuento de notas creadas, actualizadas, con cuerpo preservado y sin cambios.

La entrega de tareas no está acá, y es a propósito. Un servidor que el modelo puede invocar solo no debería poder subir una entrega a Canvas.

Cómo convive con las notas que ya existen

  1. Reutiliza la carpeta del curso. Antes de crear <course_id>-<slug> busca una carpeta que ya empiece con ese course_id y la usa tal cual. Si hay más de una, gana la que está dentro de la carpeta del semestre y el resultado lo reporta como aviso.

  2. El frontmatter es del servidor; el cuerpo es tuyo. Las notas nuevas llevan el cuerpo generado entre <!-- canvas:inicio --> y <!-- canvas:fin -->, con una sección ## Notas debajo para lo que escribas. Al volver a sincronizar solo se regenera ese bloque. Una nota sin centinelas —las que venían de otro exportador— conserva su cuerpo intacto y solo recibe el frontmatter actualizado.

  3. Los tags se unen, no se reemplazan. Se reescriben únicamente los que el servidor gestiona (canvas, canvas/*, AAAA-N, primer|segundo-semestre y los del mapa temático). Los que pusiste a mano quedan.

  4. Respeta el fin de línea de cada archivo. Una nota en CRLF se reescribe en CRLF. Sin esto, una sola pasada reescribiría el vault completo sin cambiar un dato.

  5. Si nada cambió, no escribe. La segunda pasada sobre el mismo curso reporta sin_cambios y no toca el disco.

Seguridad

  • Las peticiones solo salen hacia CANVAS_BASE_URL y únicamente a rutas /api/v1/; los enlaces de paginación que apunten a otro lado se rechazan.

  • redirect: "manual" en todo. La cookie se manda solo al origen de Canvas: una descarga que redirige a un CDN externo viaja sin cookie.

  • Toda ruta de escritura se resuelve y se verifica contra la raíz del vault o la carpeta de salida.

  • Escritura atómica (archivo temporal más rename), tope de páginas, timeouts y límites de tamaño en cada descarga.

  • Los PDF se validan por content-type, firma %PDF- y SHA-256 contra el archivo que ya exista.

Desarrollo

npm run check   # node --check
npm test        # node --test

Las pruebas mockean fetch y escriben en carpetas temporales: no tocan Canvas ni ningún vault. Hay un grupo de pruebas de paridad con bloques de frontmatter copiados de notas reales; si fallan, el servidor dejó de hablar el idioma del vault.

Licencia

MIT.

Available Tools

12 tools
canvas_course_inventoryC

Cuenta módulos, páginas, tareas, archivos, anuncios y discusiones, y actualiza la nota de curso con esos conteos.

Inputs: term, dry_run, course_id.

canvas_course_updatesC

Lista anuncios, archivos y módulos de un curso y escribe sus notas en el vault.

Inputs: course_id (required), since, dry_run.

canvas_download_course_filesC

Descarga los archivos de un curso a la carpeta Descargas del vault y actualiza sus notas.

Inputs: course_id (required), force, dry_run.

canvas_download_pdfC

Descarga un PDF verificado del curso a la carpeta de salida y deja su nota en el vault.

Inputs: file_id (required), course_id (required), dry_run.

canvas_export_course_sourcesC

Guarda las instrucciones originales, páginas, módulos, enlaces y adjuntos de un curso como JSON en la carpeta de salida.

Inputs: course_id (required).

canvas_list_active_tasksC

Lista tareas publicadas aún no enviadas y no bloqueadas del semestre más reciente, y escribe sus notas en el vault.

Inputs: term, dry_run, all_terms, course_id.

canvas_list_course_assignmentsC

Lista todas las tareas de un curso con estado de envío y escribe sus notas en el vault.

Inputs: course_id (required), dry_run.

canvas_list_coursesC

Lista los cursos activos y deja una nota de curso por cada uno en el vault, más el índice del semestre.

Inputs: dry_run.

canvas_sync_all_coursesC

Sincroniza al vault todos los cursos de un semestre y actualiza el índice.

Inputs: term, dry_run, all_terms, page_bodies, +3 more.

canvas_sync_courseC

Sincroniza un curso completo al vault: curso, archivos, tareas, páginas, módulos, anuncios y discusiones.

Inputs: course_id (required), dry_run, download_files, include_discussions, +1 more.

canvas_test_connectionA

Comprueba la sesión de Canvas con la cookie local. No escribe en el vault.

Inputs: no named parameters.

canvas_vault_statusB

Muestra dónde escribe el servidor, qué arquetipos maneja y qué carpetas de curso detecta en el vault.

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 12 tools

    Disambiguation3/5

    There is real overlap: canvas_sync_course is effectively a superset of canvas_list_course_assignments, canvas_course_updates, canvas_download_course_files, and canvas_course_inventory, so an agent must infer whether to run the full sync or the incremental partial tools. Descriptions do clarify the distinction (partial notes vs full sync, no-write vs write), which keeps it from being worse, but the boundaries are fuzzy.

    Naming Consistency4/5

    All tools share the canvas_ prefix and snake_case, and most follow verb_noun (list_courses, sync_course, download_pdf). A few deviate into noun phrasing (canvas_course_inventory, canvas_course_updates, canvas_vault_status), which is a minor inconsistency but still readable.

    Tool Count4/5

    Twelve tools is a well-scoped size for a Canvas-to-vault integration. A few partial-list tools feel like they could be folded into the sync tools, so it is slightly heavy rather than perfectly lean.

    Completeness4/5

    Coverage is strong for the sync-to-vault purpose: connection check, course/assignment/task listing, inventory, updates, full sync, downloads, raw source export, and vault status. Minor gaps exist around per-assignment detail or submission/grading views, but core lifecycle is covered.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers