@charlie.act7/canvas-mcp-server 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp.json +8 -6
- package/LICENSE +21 -0
- package/README.es.md +46 -26
- package/README.md +93 -46
- package/dist/http-server.js +139 -5
- package/dist/index.js +35 -4
- package/dist/services/agent-runner.js +214 -0
- package/dist/services/canvas-client.js +248 -5
- package/dist/services/gemini-runner.js +124 -0
- package/dist/tools/analytics-tools.js +118 -0
- package/dist/tools/assignment-tools.js +77 -1
- package/dist/tools/communication-tools.js +101 -0
- package/dist/tools/conversation-tools.js +130 -0
- package/dist/tools/course-tools.js +142 -0
- package/dist/tools/enrollment-tools.js +202 -0
- package/dist/tools/new-quiz-tools.js +357 -0
- package/dist/tools/peer-review-tools.js +130 -0
- package/dist/tools/quiz-tools.js +312 -3
- package/dist/tools/rubric-tools.js +159 -0
- package/package.json +70 -68
- package/dist/tools/question-bank-tools.js +0 -238
package/.mcp.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"canvas": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": ["-y", "@charlie.act7/canvas-mcp-server"],
|
|
6
|
+
"env": {
|
|
7
|
+
"CANVAS_API_TOKEN": "${CANVAS_API_TOKEN}",
|
|
8
|
+
"CANVAS_API_DOMAIN": "${CANVAS_API_DOMAIN}"
|
|
9
|
+
}
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Charlie Cárdenas Toledo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.es.md
CHANGED
|
@@ -3,13 +3,26 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@charlie.act7/canvas-mcp-server)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
¡Lleva tu aula virtual de Canvas al siguiente nivel con Inteligencia Artificial! 🚀
|
|
7
7
|
|
|
8
|
-
Este proyecto es un servidor de **Model Context Protocol (MCP)** para **Canvas LMS**.
|
|
8
|
+
Este proyecto es un servidor de **Model Context Protocol (MCP)** para **Canvas LMS**. Funciona como un puente que permite a asistentes de Inteligencia Artificial (como Claude Desktop, Claude Code, Cursor, etc.) consultar y administrar tus cursos de Canvas mediante instrucciones en lenguaje natural.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Tabla de Contenidos
|
|
13
|
+
- [¿Cómo funciona?](#cómo-funciona)
|
|
14
|
+
- [Ejemplos de Uso](#ejemplos-de-uso)
|
|
15
|
+
- [Guía de Instalación](#guía-de-instalación)
|
|
16
|
+
- [Paso 1: Obtener credenciales de Canvas](#paso-1-obtener-credenciales-de-canvas)
|
|
17
|
+
- [Paso 2: Configurar tu Cliente de IA](#paso-2-configurar-tu-cliente-de-ia)
|
|
18
|
+
- [Configuración por Consola (CLI)](#configuración-por-consola-cli)
|
|
19
|
+
- [Herramientas y Recursos Soportados](#herramientas-y-recursos-soportados)
|
|
20
|
+
- [Desarrollo Local](#desarrollo-local)
|
|
21
|
+
- [Licencia](#licencia)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## ¿Cómo funciona?
|
|
13
26
|
|
|
14
27
|
Cuando utilizas este servidor, la comunicación fluye de la siguiente manera:
|
|
15
28
|
|
|
@@ -23,40 +36,43 @@ graph LR
|
|
|
23
36
|
AI -->|Respuesta amigable| User
|
|
24
37
|
```
|
|
25
38
|
|
|
26
|
-
1. **Tú le pides algo
|
|
27
|
-
2. **
|
|
39
|
+
1. **Tú le pides algo al asistente** (por ejemplo: *"Crea una tarea para el próximo viernes"*).
|
|
40
|
+
2. **El asistente detecta la intención** y se comunica con el **Canvas MCP Server** enviándole los parámetros necesarios.
|
|
28
41
|
3. **El servidor realiza la llamada segura** a la API de Canvas.
|
|
29
42
|
4. **Canvas procesa la acción** y devuelve el resultado.
|
|
30
|
-
5. **
|
|
43
|
+
5. **El asistente te confirma el éxito de la operación** en lenguaje natural.
|
|
31
44
|
|
|
32
45
|
---
|
|
33
46
|
|
|
34
|
-
##
|
|
47
|
+
## Ejemplos de Uso
|
|
35
48
|
|
|
36
|
-
|
|
49
|
+
Aquí tienes algunos ejemplos de consultas y acciones reales que puedes pedirle a tu asistente:
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* 💬 *"Muéstrame las entregas pendientes de calificar para la Tarea 2 en Biología."*
|
|
41
|
-
* 💬 *"¿Cuáles son los estudiantes del Grupo B de Química?"*
|
|
42
|
-
* 💬 *"¿Qué cuestionarios o exámenes tenemos programados para esta semana?"*
|
|
51
|
+
> [!TIP]
|
|
52
|
+
> **Ahorro de Tokens y Eficiencia:** Siempre que sea posible, especifica el ID o la URL directa de Canvas (por ejemplo, `https://[tu_institucion].instructure.com/courses/[codigo_curso]/assignments/[codigo_actividad]`) en tus instrucciones. Esto evita que la IA tenga que buscar y escanear todos tus recursos, lo que resulta en respuestas mucho más rápidas y un ahorro significativo de tokens.
|
|
43
53
|
|
|
44
|
-
###
|
|
45
|
-
* 💬 *"
|
|
46
|
-
* 💬 *"
|
|
47
|
-
* 💬 *"
|
|
54
|
+
### 📖 Para Consultar Información y Auditar Cursos
|
|
55
|
+
* 💬 *"¿Qué cursos tengo activos este semestre? Verifica si existen múltiples paralelos o secciones."*
|
|
56
|
+
* 💬 *"Muéstrame las entregas pendientes de calificar para la actividad 'Ensayo 1: Introducción a la Sociología' en Sociología 101."*
|
|
57
|
+
* 💬 *"¿Cuáles son los estudiantes registrados en el Grupo A de la clase de Química?"*
|
|
58
|
+
* 💬 *"Verifica si la tarea 'Propuesta de Proyecto' tiene una rúbrica activa asociada. Si es así, obtén sus criterios."*
|
|
48
59
|
|
|
49
|
-
###
|
|
50
|
-
* 💬 *"
|
|
51
|
-
* 💬 *"
|
|
60
|
+
### ✍️ Para Administrar y Crear Contenido Académico
|
|
61
|
+
* 💬 *"Crea un nuevo módulo llamado 'Semana 1: Fundamentos' en mi curso."*
|
|
62
|
+
* 💬 *"Agrega un Subencabezado 'LECTURAS OBLIGATORIAS' dentro del módulo 'Semana 1' y enlaza la página del sílabo."*
|
|
63
|
+
* 💬 *"En mi curso de Negocios, crea una tarea llamada 'Estudio de Caso 1: Análisis de Mercado'. Agrega una tabla de instrucciones con columnas para Criterios, Requisitos y Puntaje."*
|
|
64
|
+
|
|
65
|
+
### 💯 Gestión de Calificaciones y Asistencia
|
|
66
|
+
* 💬 *"Para la tarea 'Estudio de Caso 1', busca a todos los estudiantes que no hayan entregado. Ponles un 0 de nota y agrégales el comentario: 'Actividad no entregada. Si tienes una justificación válida, por favor comunícate con el docente.'"*
|
|
67
|
+
* 💬 *"Califica la entrega de Juan en 'Ensayo 1' con un 90 basado en la rúbrica, y agrega un comentario: '¡Excelente trabajo! El análisis está muy bien estructurado, aunque podrías profundizar un poco más en las conclusiones. ¡Sigue así!'"*
|
|
52
68
|
|
|
53
69
|
---
|
|
54
70
|
|
|
55
|
-
##
|
|
71
|
+
## Guía de Instalación
|
|
56
72
|
|
|
57
73
|
Para conectar tu asistente de IA a Canvas, necesitas configurar **dos cosas**: tus credenciales de Canvas y el cliente de IA (como Claude).
|
|
58
74
|
|
|
59
|
-
### Paso 1: Obtener
|
|
75
|
+
### Paso 1: Obtener credenciales de Canvas
|
|
60
76
|
Para que el servidor pueda actuar en tu nombre, necesita permiso:
|
|
61
77
|
1. Inicia sesión en tu cuenta de **Canvas LMS**.
|
|
62
78
|
2. Dirígete a **Cuenta (Account)** ➡️ **Configuración (Settings)** en el menú lateral.
|
|
@@ -105,7 +121,7 @@ Luego, configura tus credenciales de forma interactiva:
|
|
|
105
121
|
|
|
106
122
|
---
|
|
107
123
|
|
|
108
|
-
##
|
|
124
|
+
## Configuración por Consola (CLI)
|
|
109
125
|
Si prefieres configurar las credenciales de manera local e interactiva en tu terminal para desarrollo, puedes ejecutar:
|
|
110
126
|
```bash
|
|
111
127
|
npx @charlie.act7/canvas-mcp-server config
|
|
@@ -114,8 +130,12 @@ Esto te pedirá el dominio y tu API token paso a paso, guardándolos de forma se
|
|
|
114
130
|
|
|
115
131
|
---
|
|
116
132
|
|
|
133
|
+
## Herramientas y Recursos Soportados
|
|
134
|
+
|
|
117
135
|
<details>
|
|
118
|
-
<summary
|
|
136
|
+
<summary><b>Ver Lista Detallada de Herramientas y Recursos Soportados (Técnico)</b></summary>
|
|
137
|
+
|
|
138
|
+
### Lista de Herramientas
|
|
119
139
|
|
|
120
140
|
El servidor expone internamente las siguientes herramientas organizadas por categorías:
|
|
121
141
|
|
|
@@ -144,7 +164,7 @@ Para clientes compatibles con recursos directos:
|
|
|
144
164
|
|
|
145
165
|
---
|
|
146
166
|
|
|
147
|
-
##
|
|
167
|
+
## Desarrollo Local
|
|
148
168
|
|
|
149
169
|
Si deseas clonar este repositorio y hacer modificaciones:
|
|
150
170
|
|
|
@@ -169,5 +189,5 @@ Si deseas clonar este repositorio y hacer modificaciones:
|
|
|
169
189
|
|
|
170
190
|
---
|
|
171
191
|
|
|
172
|
-
##
|
|
192
|
+
## Licencia
|
|
173
193
|
Este proyecto está bajo la licencia MIT. Creado por [Charlie Cárdenas Toledo](https://github.com/charlie-act7).
|
package/README.md
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
# 🎓 Canvas LMS MCP Server
|
|
2
2
|
|
|
3
|
+
[](https://github.com/CharlieCardenasToledo/mcp-canvas-server/actions/workflows/ci.yml)
|
|
3
4
|
[](https://www.npmjs.com/package/@charlie.act7/canvas-mcp-server)
|
|
5
|
+
[](https://www.npmjs.com/package/@charlie.act7/canvas-mcp-server)
|
|
4
6
|
[](https://opensource.org/licenses/MIT)
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
Bring AI to your Canvas Virtual Classroom! 🚀
|
|
7
9
|
|
|
8
|
-
This project is a **Model Context Protocol (MCP)** server for **Canvas LMS**.
|
|
10
|
+
This project is a **Model Context Protocol (MCP)** server for **Canvas LMS**. It acts as a bridge that allows AI assistants (like Claude Desktop, Claude Code, Cursor, etc.) to query and manage your Canvas courses using natural language.
|
|
9
11
|
|
|
10
12
|
---
|
|
11
13
|
|
|
12
|
-
##
|
|
14
|
+
## Table of Contents
|
|
15
|
+
- [How It Works](#how-it-works)
|
|
16
|
+
- [Use Cases & Examples](#use-cases--examples)
|
|
17
|
+
- [Setup Guide](#setup-guide)
|
|
18
|
+
- [Step 1: Obtain Canvas Credentials](#step-1-obtain-canvas-credentials)
|
|
19
|
+
- [Step 2: Connect to your AI Client](#step-2-connect-to-your-ai-client)
|
|
20
|
+
- [CLI Configuration](#cli-configuration)
|
|
21
|
+
- [Supported Tools & Resources](#supported-tools--resources)
|
|
22
|
+
- [Local Development](#local-development)
|
|
23
|
+
- [License](#license)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
13
28
|
|
|
14
29
|
When you interact with the server, communication flows as follows:
|
|
15
30
|
|
|
@@ -23,40 +38,64 @@ graph LR
|
|
|
23
38
|
AI -->|Friendly Answer| User
|
|
24
39
|
```
|
|
25
40
|
|
|
26
|
-
1. **You ask
|
|
27
|
-
2. **
|
|
41
|
+
1. **You ask the AI** (e.g., *"Create an assignment due next Friday"*).
|
|
42
|
+
2. **The AI detects your intent** and communicates with the **Canvas MCP Server**, sending the required parameters.
|
|
28
43
|
3. **The server makes a secure call** to the official Canvas API.
|
|
29
|
-
4. **Canvas processes the action** and returns the
|
|
30
|
-
5. **
|
|
44
|
+
4. **Canvas processes the action** and returns the response.
|
|
45
|
+
5. **The AI confirms the success of the action** back to you in plain, natural language.
|
|
31
46
|
|
|
32
47
|
---
|
|
33
48
|
|
|
34
|
-
##
|
|
49
|
+
## Use Cases & Examples
|
|
50
|
+
|
|
51
|
+
Here are some realistic, everyday prompts you can use with your AI assistant:
|
|
52
|
+
|
|
53
|
+
> [!TIP]
|
|
54
|
+
> **Token Saving & Efficiency:** Whenever possible, specify the Canvas ID or the direct Canvas URL (e.g., `https://[your_institution].instructure.com/courses/[course_id]/assignments/[assignment_id]`) in your prompts. This prevents the AI from scanning all your courses/resources, leading to faster responses and substantial token savings.
|
|
35
55
|
|
|
36
|
-
|
|
56
|
+
### 📖 Course Auditing & Querying
|
|
57
|
+
* 💬 *"What active courses do I have this semester? Check if there are multiple active sections/parallels."*
|
|
58
|
+
* 💬 *"Show me all ungraded submissions for 'Essay 1: Introduction to Sociology' in Sociology 101."*
|
|
59
|
+
* 💬 *"Who is in Student Group A for the Chemistry class?"*
|
|
60
|
+
* 💬 *"Does the assignment 'Project Proposal' have an active rubric associated? If so, retrieve its criteria."*
|
|
61
|
+
* 💬 *"Search for everything related to 'photosynthesis' across my Biology course — assignments, pages, and discussions."*
|
|
37
62
|
|
|
38
|
-
###
|
|
39
|
-
* 💬 *"
|
|
40
|
-
* 💬 *"
|
|
41
|
-
* 💬 *"
|
|
42
|
-
* 💬 *"
|
|
63
|
+
### ✍️ Creating & Organizing Course Content
|
|
64
|
+
* 💬 *"Create a new module named 'Week 1: Foundations' in my course."*
|
|
65
|
+
* 💬 *"Add a SubHeader 'REQUIRED READINGS' inside the 'Week 1' module, and link the syllabus page to it."*
|
|
66
|
+
* 💬 *"In my Business course, create an assignment called 'Case Study 1: Market Analysis'. Add an instructions table with columns for Criteria, Requirements, and Points."*
|
|
67
|
+
* 💬 *"Create a threaded discussion topic in my course titled 'Weekly Reflection' and pin it to the top."*
|
|
43
68
|
|
|
44
|
-
###
|
|
45
|
-
* 💬 *"
|
|
46
|
-
* 💬 *"
|
|
47
|
-
* 💬 *"Create a new module named 'Week 5: Introduction to React' in my course."*
|
|
69
|
+
### 💯 Grading & Absence Management
|
|
70
|
+
* 💬 *"For assignment 'Case Study 1', find all students who haven't submitted their work. Assign them a grade of 0 and add the comment: 'Activity not submitted. Please contact the instructor if you have a valid excuse.'"*
|
|
71
|
+
* 💬 *"Grade John's submission for 'Essay 1' with a 90 based on the rubric, and add a comment: 'Great job! The analysis is well-structured, though you could expand more on the conclusion. Keep it up!'"*
|
|
48
72
|
|
|
49
|
-
###
|
|
50
|
-
* 💬 *"
|
|
51
|
-
* 💬 *"
|
|
73
|
+
### 📊 Student Engagement & Analytics
|
|
74
|
+
* 💬 *"Show me the activity analytics for my Calculus course — how active have students been this week?"*
|
|
75
|
+
* 💬 *"Which students haven't been active in course 12345 in the last few days? I want to reach out to them."*
|
|
76
|
+
* 💬 *"Get the analytics for student [ID] in my Biology course — how many page views and participations do they have?"*
|
|
77
|
+
|
|
78
|
+
### 💬 Messaging & Communication
|
|
79
|
+
* 💬 *"Send a private message to student [ID] reminding them their 'Project Proposal' is due tomorrow."*
|
|
80
|
+
* 💬 *"How many unread messages do I have in my Canvas inbox?"*
|
|
81
|
+
* 💬 *"Show me my last 10 inbox conversations."*
|
|
82
|
+
|
|
83
|
+
### 👥 Enrollment & Student Management
|
|
84
|
+
* 💬 *"Who is enrolled in my course? Show me students and TAs separately."*
|
|
85
|
+
* 💬 *"Search for a student named 'Maria Gonzalez' in account 1."*
|
|
86
|
+
* 💬 *"Enroll user [ID] as a TA in my Physics course."*
|
|
87
|
+
|
|
88
|
+
### 🔄 Peer Reviews
|
|
89
|
+
* 💬 *"List all peer review assignments for 'Research Paper' in course 12345."*
|
|
90
|
+
* 💬 *"Manually assign student [ID] to review [other student ID]'s submission for 'Essay 2'."*
|
|
52
91
|
|
|
53
92
|
---
|
|
54
93
|
|
|
55
|
-
##
|
|
94
|
+
## Setup Guide
|
|
56
95
|
|
|
57
96
|
To connect your AI assistant to Canvas, you need to configure **two things**: your Canvas credentials and your AI client (like Claude).
|
|
58
97
|
|
|
59
|
-
### Step 1: Obtain
|
|
98
|
+
### Step 1: Obtain Canvas Credentials
|
|
60
99
|
To let the server act on your behalf, it needs permission:
|
|
61
100
|
1. Log in to your **Canvas LMS** account.
|
|
62
101
|
2. Go to **Account** ➡️ **Settings** in the sidebar menu.
|
|
@@ -105,7 +144,7 @@ Then, configure your credentials interactively:
|
|
|
105
144
|
|
|
106
145
|
---
|
|
107
146
|
|
|
108
|
-
##
|
|
147
|
+
## CLI Configuration
|
|
109
148
|
If you prefer to configure your credentials locally for development, run:
|
|
110
149
|
```bash
|
|
111
150
|
npx @charlie.act7/canvas-mcp-server config
|
|
@@ -114,27 +153,35 @@ This will guide you step-by-step to input your domain and API token, storing the
|
|
|
114
153
|
|
|
115
154
|
---
|
|
116
155
|
|
|
156
|
+
## Supported Tools & Resources
|
|
157
|
+
|
|
117
158
|
<details>
|
|
118
|
-
<summary
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
| Category |
|
|
123
|
-
|
|
124
|
-
| **Courses** |
|
|
125
|
-
| **Modules** |
|
|
126
|
-
| **Pages** |
|
|
127
|
-
| **Files** |
|
|
128
|
-
| **
|
|
129
|
-
| **
|
|
130
|
-
| **
|
|
131
|
-
| **
|
|
132
|
-
| **Quizzes** |
|
|
133
|
-
| **
|
|
134
|
-
| **
|
|
135
|
-
| **
|
|
136
|
-
| **
|
|
137
|
-
| **
|
|
159
|
+
<summary><b>View all 111 tools organized by category</b></summary>
|
|
160
|
+
|
|
161
|
+
### Tool Inventory
|
|
162
|
+
|
|
163
|
+
| Category | Tools | Description |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| **Courses** | `list_courses` · `create_course` · `update_course` · `get_syllabus` | Manage and configure courses |
|
|
166
|
+
| **Modules** | `list_modules` · `create_module` · `update_module` · `delete_module` · `create_module_item` · `update_module_item` · `delete_module_item` | Full CRUD for modules and their items |
|
|
167
|
+
| **Pages** | `list_pages` · `get_page_content` · `create_page` · `update_page` · `delete_page` | Manage wiki pages |
|
|
168
|
+
| **Files & Folders** | `list_files` · `upload_file` · `update_file` · `delete_file` · `list_folders` · `create_folder` · `update_folder` · `delete_folder` | File management with folder support |
|
|
169
|
+
| **Assignments** | `get_assignments` · `get_assignment` · `create_assignment` · `update_assignment` · `delete_assignment` · `update_assignment_dates` · `bulk_update_due_dates` · `list_assignment_groups` | Full assignment lifecycle |
|
|
170
|
+
| **Submissions** | `get_submissions` · `get_submission` · `get_submission_comments` · `delete_submission_comment` · `submit_assignment` | View and manage student submissions |
|
|
171
|
+
| **Grading** | `grade_submission` · `grade_multiple_submissions` · `audit_course` | Grade individually or in bulk |
|
|
172
|
+
| **Rubrics** | `list_rubrics` · `get_rubric` · `create_rubric` · `update_rubric` · `create_rubric_association` | Build and attach grading rubrics |
|
|
173
|
+
| **Quizzes (Classic)** | `list_quizzes` · `get_quiz` · `create_quiz` · `update_quiz` · `update_quiz_dates` · `list_quiz_questions` · `get_quiz_question` · `create_quiz_question` · `update_quiz_question` · `delete_quiz_question` · `create_quiz_group` | Classic Canvas quiz engine |
|
|
174
|
+
| **New Quizzes (LTI)** | `create_new_quiz` · `update_new_quiz` · `delete_new_quiz` · `list_new_quiz_items` · `get_new_quiz_item` · `create_new_quiz_item` · `update_new_quiz_item` · `delete_new_quiz_item` | Modern LTI quiz engine (`/api/quiz/v1`) |
|
|
175
|
+
| **Students** | `list_students` · `list_students_with_grades` · `get_student_grades` · `get_student_assignments` · `list_assignment_due_dates` | Roster and progress tracking |
|
|
176
|
+
| **Enrollments** | `list_course_enrollments` · `enroll_user` · `remove_enrollment` · `get_user` · `get_profile` · `search_users` | Manage who is in your course |
|
|
177
|
+
| **Groups** | `list_group_categories` · `create_group_category` · `list_groups_in_category` · `create_group` · `assign_unassigned_members` · `add_group_member` | Student group management |
|
|
178
|
+
| **Discussions** | `list_discussions` · `get_discussion_entries` · `create_discussion` · `delete_discussion` · `post_discussion_reply` | Discussion boards |
|
|
179
|
+
| **Announcements** | `list_announcements` · `post_announcement` · `update_announcement` | Course announcements |
|
|
180
|
+
| **Conversations** | `list_conversations` · `get_conversation` · `get_conversation_unread_count` · `send_conversation` · `reply_to_conversation` | Private inbox messaging |
|
|
181
|
+
| **Calendar** | `list_appointment_groups` · `get_appointment_group` · `create_appointment_group` · `update_appointment_group` · `delete_appointment_group` · `list_appointment_group_users` · `list_appointment_group_groups` · `get_next_appointment` | Scheduling and appointments |
|
|
182
|
+
| **Analytics** | `get_course_analytics` · `get_student_analytics` · `get_course_activity_stream` · `search_course_content` | Engagement data and content search |
|
|
183
|
+
| **Peer Reviews** | `list_peer_reviews` · `get_submission_peer_reviews` · `create_peer_review` · `delete_peer_review` | Configure and manage peer assessments |
|
|
184
|
+
| **Health & Config** | `health_check` · `set_canvas_config` | Verify connection and update credentials at runtime |
|
|
138
185
|
|
|
139
186
|
### Supported MCP Resources
|
|
140
187
|
For clients supporting direct resources:
|
|
@@ -144,7 +191,7 @@ For clients supporting direct resources:
|
|
|
144
191
|
|
|
145
192
|
---
|
|
146
193
|
|
|
147
|
-
##
|
|
194
|
+
## Local Development
|
|
148
195
|
|
|
149
196
|
To clone this repository and modify the code:
|
|
150
197
|
|
|
@@ -169,5 +216,5 @@ To clone this repository and modify the code:
|
|
|
169
216
|
|
|
170
217
|
---
|
|
171
218
|
|
|
172
|
-
##
|
|
219
|
+
## License
|
|
173
220
|
This project is licensed under the MIT License. Created by [Charlie Cárdenas Toledo](https://github.com/charlie-act7).
|
package/dist/http-server.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import Fastify from "fastify";
|
|
2
2
|
import swagger from "@fastify/swagger";
|
|
3
3
|
import swaggerUi from "@fastify/swagger-ui";
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { AgentRunner } from "./services/agent-runner.js";
|
|
7
|
+
import { GeminiRunner } from "./services/gemini-runner.js";
|
|
4
8
|
function buildOpenApiSpec() {
|
|
5
9
|
return {
|
|
6
10
|
openapi: "3.1.0",
|
|
@@ -21,7 +25,12 @@ function buildOpenApiSpec() {
|
|
|
21
25
|
summary: "Health check",
|
|
22
26
|
responses: {
|
|
23
27
|
"200": {
|
|
24
|
-
description: "Server is healthy"
|
|
28
|
+
description: "Server is healthy",
|
|
29
|
+
content: {
|
|
30
|
+
"application/json": {
|
|
31
|
+
schema: { type: "object", properties: { ok: { type: "boolean" } } }
|
|
32
|
+
}
|
|
33
|
+
}
|
|
25
34
|
}
|
|
26
35
|
}
|
|
27
36
|
}
|
|
@@ -32,7 +41,20 @@ function buildOpenApiSpec() {
|
|
|
32
41
|
summary: "Privacy policy",
|
|
33
42
|
responses: {
|
|
34
43
|
"200": {
|
|
35
|
-
description: "Privacy policy text"
|
|
44
|
+
description: "Privacy policy text",
|
|
45
|
+
content: {
|
|
46
|
+
"application/json": {
|
|
47
|
+
schema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
service: { type: "string" },
|
|
51
|
+
effective_date: { type: "string" },
|
|
52
|
+
summary: { type: "array", items: { type: "string" } },
|
|
53
|
+
contact: { type: "string" }
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
36
58
|
}
|
|
37
59
|
}
|
|
38
60
|
}
|
|
@@ -43,7 +65,24 @@ function buildOpenApiSpec() {
|
|
|
43
65
|
summary: "List active Canvas courses",
|
|
44
66
|
responses: {
|
|
45
67
|
"200": {
|
|
46
|
-
description: "Courses list"
|
|
68
|
+
description: "Courses list",
|
|
69
|
+
content: {
|
|
70
|
+
"application/json": {
|
|
71
|
+
schema: {
|
|
72
|
+
type: "array",
|
|
73
|
+
items: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
id: { type: "integer" },
|
|
77
|
+
name: { type: "string" },
|
|
78
|
+
course_code: { type: "string" },
|
|
79
|
+
workflow_state: { type: "string" },
|
|
80
|
+
enrollment_term_id: { type: "integer" }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
47
86
|
}
|
|
48
87
|
}
|
|
49
88
|
}
|
|
@@ -86,7 +125,26 @@ function buildOpenApiSpec() {
|
|
|
86
125
|
],
|
|
87
126
|
responses: {
|
|
88
127
|
"200": {
|
|
89
|
-
description: "Assignments list"
|
|
128
|
+
description: "Assignments list",
|
|
129
|
+
content: {
|
|
130
|
+
"application/json": {
|
|
131
|
+
schema: {
|
|
132
|
+
type: "array",
|
|
133
|
+
items: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {
|
|
136
|
+
id: { type: "integer" },
|
|
137
|
+
name: { type: "string" },
|
|
138
|
+
due_at: { type: "string", nullable: true },
|
|
139
|
+
unlock_at: { type: "string", nullable: true },
|
|
140
|
+
lock_at: { type: "string", nullable: true },
|
|
141
|
+
points_possible: { type: "number", nullable: true },
|
|
142
|
+
published: { type: "boolean", nullable: true }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
90
148
|
}
|
|
91
149
|
}
|
|
92
150
|
}
|
|
@@ -527,7 +585,7 @@ function buildOpenApiSpec() {
|
|
|
527
585
|
}
|
|
528
586
|
};
|
|
529
587
|
}
|
|
530
|
-
export async function startHttpServer(client, host = "0.0.0.0", port = 3000) {
|
|
588
|
+
export async function startHttpServer(client, host = "0.0.0.0", port = 3000, tools = []) {
|
|
531
589
|
const app = Fastify({ logger: true });
|
|
532
590
|
await app.register(swagger, {
|
|
533
591
|
openapi: buildOpenApiSpec()
|
|
@@ -535,6 +593,11 @@ export async function startHttpServer(client, host = "0.0.0.0", port = 3000) {
|
|
|
535
593
|
await app.register(swaggerUi, {
|
|
536
594
|
routePrefix: "/docs"
|
|
537
595
|
});
|
|
596
|
+
app.setErrorHandler((error, _request, reply) => {
|
|
597
|
+
const status = error.statusCode ?? 500;
|
|
598
|
+
const message = status >= 500 ? "Internal server error" : error.message;
|
|
599
|
+
reply.code(status).send({ error: message });
|
|
600
|
+
});
|
|
538
601
|
app.get("/health", async () => ({ ok: true }));
|
|
539
602
|
app.get("/privacy", async () => ({
|
|
540
603
|
service: "Canvas MCP HTTP API",
|
|
@@ -756,5 +819,76 @@ export async function startHttpServer(client, host = "0.0.0.0", port = 3000) {
|
|
|
756
819
|
results
|
|
757
820
|
};
|
|
758
821
|
});
|
|
822
|
+
// --- POST /chat ---
|
|
823
|
+
const ollamaRunner = new AgentRunner(client, tools, process.env.OLLAMA_HOST ?? "http://localhost:11434");
|
|
824
|
+
const GEMINI_API_KEY = process.env.GEMINI_API_KEY ?? "";
|
|
825
|
+
const geminiRunner = GEMINI_API_KEY
|
|
826
|
+
? new GeminiRunner(GEMINI_API_KEY, client, tools)
|
|
827
|
+
: null;
|
|
828
|
+
app.post("/chat", async (request, reply) => {
|
|
829
|
+
const { message, model, mode, provider = "ollama", gemini_key } = request.body ?? {};
|
|
830
|
+
if (!message || typeof message !== "string" || !message.trim()) {
|
|
831
|
+
return reply.code(400).send({ error: "El campo 'message' es requerido." });
|
|
832
|
+
}
|
|
833
|
+
if (tools.length === 0) {
|
|
834
|
+
return reply.code(503).send({ error: "El servidor no tiene herramientas cargadas. Inicia con 'serve-http'." });
|
|
835
|
+
}
|
|
836
|
+
if (provider === "gemini") {
|
|
837
|
+
const apiKey = gemini_key || GEMINI_API_KEY;
|
|
838
|
+
if (!apiKey) {
|
|
839
|
+
return reply.code(400).send({ error: "Se necesita gemini_key en el body o GEMINI_API_KEY en el entorno." });
|
|
840
|
+
}
|
|
841
|
+
const runner = gemini_key
|
|
842
|
+
? new GeminiRunner(gemini_key, client, tools)
|
|
843
|
+
: geminiRunner;
|
|
844
|
+
return runner.run(message.trim(), { model });
|
|
845
|
+
}
|
|
846
|
+
return ollamaRunner.run(message.trim(), { model, mode });
|
|
847
|
+
});
|
|
848
|
+
// --- POST /audit ---
|
|
849
|
+
const SKILL_PATH = process.env.AUDIT_SKILL_PATH ?? path.resolve(process.env.USERPROFILE ?? process.env.HOME ?? ".", "Proyectos Personales", "material-docente - UIDE", ".claude", "commands", "canvas-module-auditor-uide-v2.md");
|
|
850
|
+
app.post("/audit", async (request, reply) => {
|
|
851
|
+
const { course_id, week, course_name, provider = "gemini", model, gemini_key } = request.body ?? {};
|
|
852
|
+
if (!course_id || !week) {
|
|
853
|
+
return reply.code(400).send({ error: "course_id y week son requeridos." });
|
|
854
|
+
}
|
|
855
|
+
if (tools.length === 0) {
|
|
856
|
+
return reply.code(503).send({ error: "El servidor no tiene herramientas cargadas." });
|
|
857
|
+
}
|
|
858
|
+
// Leer el skill de auditoría
|
|
859
|
+
let skillContent;
|
|
860
|
+
try {
|
|
861
|
+
skillContent = await fs.readFile(SKILL_PATH, "utf-8");
|
|
862
|
+
}
|
|
863
|
+
catch {
|
|
864
|
+
return reply.code(500).send({
|
|
865
|
+
error: `No se encontró el archivo de skill en: ${SKILL_PATH}. Define AUDIT_SKILL_PATH como variable de entorno.`
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
// Construir el mensaje de auditoría
|
|
869
|
+
const courseLabel = course_name ? `${course_name} (course_id: ${course_id})` : `course_id: ${course_id}`;
|
|
870
|
+
const auditMessage = `Ejecuta una auditoría instruccional completa de la Semana ${week} del curso ${courseLabel}. ` +
|
|
871
|
+
`Sigue exactamente el flujo de los pasos 1 al 4 definidos en las instrucciones. ` +
|
|
872
|
+
`Genera el reporte markdown completo con todas las secciones y la calificación global.`;
|
|
873
|
+
if (provider === "gemini") {
|
|
874
|
+
const apiKey = gemini_key || GEMINI_API_KEY;
|
|
875
|
+
if (!apiKey) {
|
|
876
|
+
return reply.code(400).send({ error: "Se necesita gemini_key en el body o GEMINI_API_KEY en el entorno." });
|
|
877
|
+
}
|
|
878
|
+
const runner = gemini_key
|
|
879
|
+
? new GeminiRunner(gemini_key, client, tools)
|
|
880
|
+
: geminiRunner;
|
|
881
|
+
const result = await runner.run(auditMessage, {
|
|
882
|
+
model: model ?? "gemini-2.5-flash",
|
|
883
|
+
systemPrompt: skillContent
|
|
884
|
+
});
|
|
885
|
+
return { ...result, course_id, week };
|
|
886
|
+
}
|
|
887
|
+
const result = await ollamaRunner.run(auditMessage, {
|
|
888
|
+
model,
|
|
889
|
+
systemPrompt: skillContent
|
|
890
|
+
});
|
|
891
|
+
return { ...result, course_id, week };
|
|
892
|
+
});
|
|
759
893
|
await app.listen({ host, port });
|
|
760
894
|
}
|