@charlie.act7/canvas-mcp-server 1.1.8 → 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.md +49 -22
- 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
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { resolveCourseId } from "../common/helpers.js";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
export const questionBankTools = [
|
|
4
|
-
{
|
|
5
|
-
name: "canvas_list_question_banks",
|
|
6
|
-
tool: {
|
|
7
|
-
name: "canvas_list_question_banks",
|
|
8
|
-
description: "List question banks for a specific course",
|
|
9
|
-
inputSchema: {
|
|
10
|
-
type: "object",
|
|
11
|
-
properties: {
|
|
12
|
-
course_id: {
|
|
13
|
-
anyOf: [{ type: "number" }, { type: "string" }],
|
|
14
|
-
description: "The ID or name of the course"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
required: ["course_id"]
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
handler: async (client, args) => {
|
|
21
|
-
const input = z.object({ course_id: z.union([z.number(), z.string()]) }).parse(args);
|
|
22
|
-
const courseId = await resolveCourseId(client, input.course_id);
|
|
23
|
-
const banks = await client.listQuestionBanks(courseId);
|
|
24
|
-
return {
|
|
25
|
-
content: [{ type: "text", text: JSON.stringify(banks, null, 2) }]
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: "canvas_create_question_bank",
|
|
31
|
-
tool: {
|
|
32
|
-
name: "canvas_create_question_bank",
|
|
33
|
-
description: "Create a new question bank in a course",
|
|
34
|
-
inputSchema: {
|
|
35
|
-
type: "object",
|
|
36
|
-
properties: {
|
|
37
|
-
course_id: {
|
|
38
|
-
anyOf: [{ type: "number" }, { type: "string" }],
|
|
39
|
-
description: "The ID or name of the course"
|
|
40
|
-
},
|
|
41
|
-
title: {
|
|
42
|
-
type: "string",
|
|
43
|
-
description: "Title for the question bank"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
required: ["course_id", "title"]
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
handler: async (client, args) => {
|
|
50
|
-
const input = z.object({
|
|
51
|
-
course_id: z.union([z.number(), z.string()]),
|
|
52
|
-
title: z.string().min(1)
|
|
53
|
-
}).parse(args);
|
|
54
|
-
const courseId = await resolveCourseId(client, input.course_id);
|
|
55
|
-
const bank = await client.createQuestionBank(courseId, input.title);
|
|
56
|
-
return {
|
|
57
|
-
content: [{ type: "text", text: JSON.stringify(bank, null, 2) }]
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
name: "canvas_create_assessment_question",
|
|
63
|
-
tool: {
|
|
64
|
-
name: "canvas_create_assessment_question",
|
|
65
|
-
description: "Create a question in a question bank. Supports types: multiple_choice_question, true_false_question, essay_question, short_answer_question, fill_in_multiple_blanks_question, multiple_answers_question, matching_question, numerical_question.",
|
|
66
|
-
inputSchema: {
|
|
67
|
-
type: "object",
|
|
68
|
-
properties: {
|
|
69
|
-
course_id: {
|
|
70
|
-
anyOf: [{ type: "number" }, { type: "string" }],
|
|
71
|
-
description: "The ID or name of the course"
|
|
72
|
-
},
|
|
73
|
-
bank_id: {
|
|
74
|
-
type: "number",
|
|
75
|
-
description: "The question bank ID"
|
|
76
|
-
},
|
|
77
|
-
name: {
|
|
78
|
-
type: "string",
|
|
79
|
-
description: "Short name/title for the question"
|
|
80
|
-
},
|
|
81
|
-
question_type: {
|
|
82
|
-
type: "string",
|
|
83
|
-
description: "Question type (e.g. multiple_choice_question, true_false_question, essay_question, short_answer_question)"
|
|
84
|
-
},
|
|
85
|
-
question_text: {
|
|
86
|
-
type: "string",
|
|
87
|
-
description: "The question text (HTML supported)"
|
|
88
|
-
},
|
|
89
|
-
points_possible: {
|
|
90
|
-
type: "number",
|
|
91
|
-
description: "Point value for the question"
|
|
92
|
-
},
|
|
93
|
-
answers: {
|
|
94
|
-
type: "array",
|
|
95
|
-
description: "Array of answer objects. For multiple_choice: weight=100 for correct, weight=0 for incorrect. For true_false: text='True'/'False'.",
|
|
96
|
-
items: {
|
|
97
|
-
type: "object",
|
|
98
|
-
properties: {
|
|
99
|
-
text: { type: "string", description: "Answer text" },
|
|
100
|
-
weight: { type: "number", description: "100 for correct, 0 for incorrect" },
|
|
101
|
-
comments: { type: "string", description: "Optional feedback comment" }
|
|
102
|
-
},
|
|
103
|
-
required: ["text", "weight"]
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
required: ["course_id", "bank_id", "name", "question_type", "question_text", "points_possible"]
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
handler: async (client, args) => {
|
|
111
|
-
const answerSchema = z.object({
|
|
112
|
-
text: z.string(),
|
|
113
|
-
weight: z.number(),
|
|
114
|
-
comments: z.string().optional()
|
|
115
|
-
});
|
|
116
|
-
const input = z.object({
|
|
117
|
-
course_id: z.union([z.number(), z.string()]),
|
|
118
|
-
bank_id: z.coerce.number(),
|
|
119
|
-
name: z.string().min(1),
|
|
120
|
-
question_type: z.string().min(1),
|
|
121
|
-
question_text: z.string().min(1),
|
|
122
|
-
points_possible: z.coerce.number(),
|
|
123
|
-
answers: z.array(answerSchema).optional()
|
|
124
|
-
}).parse(args);
|
|
125
|
-
const courseId = await resolveCourseId(client, input.course_id);
|
|
126
|
-
const question = await client.createAssessmentQuestion(courseId, input.bank_id, {
|
|
127
|
-
name: input.name,
|
|
128
|
-
question_type: input.question_type,
|
|
129
|
-
question_text: input.question_text,
|
|
130
|
-
points_possible: input.points_possible,
|
|
131
|
-
answers: input.answers
|
|
132
|
-
});
|
|
133
|
-
return {
|
|
134
|
-
content: [{ type: "text", text: JSON.stringify(question, null, 2) }]
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: "canvas_move_question_bank_questions",
|
|
140
|
-
tool: {
|
|
141
|
-
name: "canvas_move_question_bank_questions",
|
|
142
|
-
description: "Move questions from one question bank to another. If question_ids is omitted, all questions are moved.",
|
|
143
|
-
inputSchema: {
|
|
144
|
-
type: "object",
|
|
145
|
-
properties: {
|
|
146
|
-
course_id: {
|
|
147
|
-
anyOf: [{ type: "number" }, { type: "string" }],
|
|
148
|
-
description: "The ID or name of the course"
|
|
149
|
-
},
|
|
150
|
-
source_bank_id: {
|
|
151
|
-
type: "number",
|
|
152
|
-
description: "Source question bank ID"
|
|
153
|
-
},
|
|
154
|
-
dest_bank_id: {
|
|
155
|
-
type: "number",
|
|
156
|
-
description: "Destination question bank ID"
|
|
157
|
-
},
|
|
158
|
-
question_ids: {
|
|
159
|
-
type: "array",
|
|
160
|
-
items: { type: "number" },
|
|
161
|
-
description: "Optional list of specific question IDs to move. If omitted, all questions are moved."
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
required: ["course_id", "source_bank_id", "dest_bank_id"]
|
|
165
|
-
}
|
|
166
|
-
},
|
|
167
|
-
handler: async (client, args) => {
|
|
168
|
-
const input = z.object({
|
|
169
|
-
course_id: z.union([z.number(), z.string()]),
|
|
170
|
-
source_bank_id: z.coerce.number(),
|
|
171
|
-
dest_bank_id: z.coerce.number(),
|
|
172
|
-
question_ids: z.array(z.coerce.number()).optional()
|
|
173
|
-
}).parse(args);
|
|
174
|
-
const courseId = await resolveCourseId(client, input.course_id);
|
|
175
|
-
const result = await client.moveQuestionBankQuestions(courseId, input.source_bank_id, input.dest_bank_id, input.question_ids);
|
|
176
|
-
return {
|
|
177
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: "canvas_create_quiz_group",
|
|
183
|
-
tool: {
|
|
184
|
-
name: "canvas_create_quiz_group",
|
|
185
|
-
description: "Create a quiz group linked to a question bank. The group randomly picks questions from the bank when students take the quiz.",
|
|
186
|
-
inputSchema: {
|
|
187
|
-
type: "object",
|
|
188
|
-
properties: {
|
|
189
|
-
course_id: {
|
|
190
|
-
anyOf: [{ type: "number" }, { type: "string" }],
|
|
191
|
-
description: "The ID or name of the course"
|
|
192
|
-
},
|
|
193
|
-
quiz_id: {
|
|
194
|
-
type: "number",
|
|
195
|
-
description: "The quiz ID"
|
|
196
|
-
},
|
|
197
|
-
name: {
|
|
198
|
-
type: "string",
|
|
199
|
-
description: "Name for the quiz group"
|
|
200
|
-
},
|
|
201
|
-
pick_count: {
|
|
202
|
-
type: "number",
|
|
203
|
-
description: "Number of questions to randomly pick from the bank"
|
|
204
|
-
},
|
|
205
|
-
question_points: {
|
|
206
|
-
type: "number",
|
|
207
|
-
description: "Points per question in this group"
|
|
208
|
-
},
|
|
209
|
-
assessment_question_bank_id: {
|
|
210
|
-
type: "number",
|
|
211
|
-
description: "The question bank ID to link to this group"
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
required: ["course_id", "quiz_id", "name", "pick_count", "question_points"]
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
handler: async (client, args) => {
|
|
218
|
-
const input = z.object({
|
|
219
|
-
course_id: z.union([z.number(), z.string()]),
|
|
220
|
-
quiz_id: z.coerce.number(),
|
|
221
|
-
name: z.string().min(1),
|
|
222
|
-
pick_count: z.coerce.number().min(1),
|
|
223
|
-
question_points: z.coerce.number().min(0),
|
|
224
|
-
assessment_question_bank_id: z.coerce.number().optional()
|
|
225
|
-
}).parse(args);
|
|
226
|
-
const courseId = await resolveCourseId(client, input.course_id);
|
|
227
|
-
const group = await client.createQuizGroup(courseId, input.quiz_id, {
|
|
228
|
-
name: input.name,
|
|
229
|
-
pick_count: input.pick_count,
|
|
230
|
-
question_points: input.question_points,
|
|
231
|
-
assessment_question_bank_id: input.assessment_question_bank_id
|
|
232
|
-
});
|
|
233
|
-
return {
|
|
234
|
-
content: [{ type: "text", text: JSON.stringify(group, null, 2) }]
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
];
|