@charlie.act7/canvas-mcp-server 1.1.8 → 1.2.1

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.
@@ -63,7 +63,7 @@ export const moduleTools = [
63
63
  name: "canvas_update_module",
64
64
  tool: {
65
65
  name: "canvas_update_module",
66
- description: "Update an existing module",
66
+ description: "Update an existing module (name, published, position, prerequisites, completion requirements)",
67
67
  inputSchema: {
68
68
  type: "object",
69
69
  properties: {
@@ -74,7 +74,32 @@ export const moduleTools = [
74
74
  module_id: { type: "number", description: "The ID of the module" },
75
75
  name: { type: "string", description: "The new name of the module" },
76
76
  published: { type: "boolean", description: "Whether the module is published" },
77
- position: { type: "number", description: "The new position of the module" }
77
+ position: { type: "number", description: "The new position of the module" },
78
+ prerequisite_module_ids: {
79
+ type: "array",
80
+ items: { type: "number" },
81
+ description: "IDs of modules that must be completed before this one unlocks"
82
+ },
83
+ require_sequential_progress: {
84
+ type: "boolean",
85
+ description: "Whether items in the module must be completed in order"
86
+ },
87
+ completion_requirements: {
88
+ type: "array",
89
+ description: "Completion requirements for module items. Replaces ALL existing requirements — include every item that needs one.",
90
+ items: {
91
+ type: "object",
92
+ properties: {
93
+ id: { type: "number", description: "The module item ID" },
94
+ type: {
95
+ type: "string",
96
+ description: "must_view, must_submit, must_contribute, min_score, must_mark_done"
97
+ },
98
+ min_score: { type: "number", description: "Required when type is min_score" }
99
+ },
100
+ required: ["id", "type"]
101
+ }
102
+ }
78
103
  },
79
104
  required: ["course_id", "module_id"],
80
105
  },
@@ -85,13 +110,23 @@ export const moduleTools = [
85
110
  module_id: z.number(),
86
111
  name: z.string().optional(),
87
112
  published: z.boolean().optional(),
88
- position: z.number().optional()
113
+ position: z.number().optional(),
114
+ prerequisite_module_ids: z.array(z.number()).optional(),
115
+ require_sequential_progress: z.boolean().optional(),
116
+ completion_requirements: z.array(z.object({
117
+ id: z.number(),
118
+ type: z.string(),
119
+ min_score: z.number().optional()
120
+ })).optional()
89
121
  }).parse(args);
90
122
  const courseId = await resolveCourseId(client, input.course_id);
91
123
  const module = await client.updateModule(courseId, input.module_id, {
92
124
  name: input.name,
93
125
  published: input.published,
94
- position: input.position
126
+ position: input.position,
127
+ prerequisite_module_ids: input.prerequisite_module_ids,
128
+ require_sequential_progress: input.require_sequential_progress,
129
+ completion_requirements: input.completion_requirements
95
130
  });
96
131
  return {
97
132
  content: [{ type: "text", text: JSON.stringify(module, null, 2) }],
@@ -206,7 +241,11 @@ export const moduleTools = [
206
241
  position: { type: "number", description: "The new position of the item" },
207
242
  indent: { type: "number", description: "The new level of indentation (0-3)" },
208
243
  published: { type: "boolean", description: "Whether the item is published" },
209
- new_module_id: { type: "number", description: "Move the item to a new module" }
244
+ new_module_id: { type: "number", description: "Move the item to a new module" },
245
+ completion_requirement_type: {
246
+ type: "string",
247
+ description: "Completion requirement type: must_view, must_submit, must_contribute, min_score, must_mark_done"
248
+ }
210
249
  },
211
250
  required: ["course_id", "module_id", "item_id"],
212
251
  },
@@ -220,7 +259,8 @@ export const moduleTools = [
220
259
  position: z.number().optional(),
221
260
  indent: z.number().optional(),
222
261
  published: z.boolean().optional(),
223
- new_module_id: z.number().optional()
262
+ new_module_id: z.number().optional(),
263
+ completion_requirement_type: z.string().optional()
224
264
  }).parse(args);
225
265
  const courseId = await resolveCourseId(client, input.course_id);
226
266
  const result = await client.updateModuleItem(courseId, input.module_id, input.item_id, {
@@ -228,7 +268,10 @@ export const moduleTools = [
228
268
  position: input.position,
229
269
  indent: input.indent,
230
270
  published: input.published,
231
- module_id: input.new_module_id
271
+ module_id: input.new_module_id,
272
+ ...(input.completion_requirement_type && {
273
+ completion_requirement: { type: input.completion_requirement_type }
274
+ })
232
275
  });
233
276
  return {
234
277
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
@@ -0,0 +1,357 @@
1
+ import { resolveCourseId } from "../common/helpers.js";
2
+ import { z } from "zod";
3
+ export const newQuizTools = [
4
+ {
5
+ name: "canvas_create_new_quiz",
6
+ tool: {
7
+ name: "canvas_create_new_quiz",
8
+ description: "Create a New Quiz (LTI) in a course. Use this for Canvas's modern quiz engine (not Classic Quizzes).",
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
+ title: { type: "string", description: "Quiz title" },
17
+ instructions: { type: "string", description: "HTML instructions shown to students before starting" },
18
+ due_at: { type: "string", description: "Due date (ISO 8601)" },
19
+ lock_at: { type: "string", description: "Lock date (ISO 8601)" },
20
+ unlock_at: { type: "string", description: "Available from date (ISO 8601)" },
21
+ points_possible: { type: "number", description: "Total points possible" },
22
+ time_limit: { type: "number", description: "Time limit in minutes (null for no limit)" },
23
+ allowed_attempts: { type: "number", description: "Number of attempts allowed (-1 for unlimited)" },
24
+ shuffle_answers: { type: "boolean", description: "Randomize answer order" },
25
+ shuffle_questions: { type: "boolean", description: "Randomize question order" },
26
+ one_question_at_a_time: { type: "boolean", description: "Show one question per page" },
27
+ cant_go_back: { type: "boolean", description: "Prevent going back to previous questions" },
28
+ show_correct_answers: { type: "boolean", description: "Show correct answers after submission" }
29
+ },
30
+ required: ["course_id", "title"],
31
+ },
32
+ },
33
+ handler: async (client, args) => {
34
+ const input = z.object({
35
+ course_id: z.union([z.number(), z.string()]),
36
+ title: z.string(),
37
+ instructions: z.string().optional(),
38
+ due_at: z.string().optional(),
39
+ lock_at: z.string().optional(),
40
+ unlock_at: z.string().optional(),
41
+ points_possible: z.number().optional(),
42
+ time_limit: z.number().optional(),
43
+ allowed_attempts: z.number().optional(),
44
+ shuffle_answers: z.boolean().optional(),
45
+ shuffle_questions: z.boolean().optional(),
46
+ one_question_at_a_time: z.boolean().optional(),
47
+ cant_go_back: z.boolean().optional(),
48
+ show_correct_answers: z.boolean().optional()
49
+ }).parse(args);
50
+ const courseId = await resolveCourseId(client, input.course_id);
51
+ const { course_id: _, ...quizData } = input;
52
+ const result = await client.createNewQuiz(courseId, quizData);
53
+ return {
54
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
55
+ };
56
+ }
57
+ },
58
+ {
59
+ name: "canvas_update_new_quiz",
60
+ tool: {
61
+ name: "canvas_update_new_quiz",
62
+ description: "Update an existing New Quiz (LTI)",
63
+ inputSchema: {
64
+ type: "object",
65
+ properties: {
66
+ course_id: {
67
+ anyOf: [{ type: "number" }, { type: "string" }],
68
+ description: "The ID or name of the course"
69
+ },
70
+ quiz_id: { type: "string", description: "The New Quiz ID (assignment ID)" },
71
+ title: { type: "string" },
72
+ instructions: { type: "string" },
73
+ due_at: { type: "string", description: "ISO 8601 date or null to clear" },
74
+ lock_at: { type: "string" },
75
+ unlock_at: { type: "string" },
76
+ points_possible: { type: "number" },
77
+ time_limit: { type: "number", description: "Minutes (null to remove limit)" },
78
+ allowed_attempts: { type: "number" },
79
+ shuffle_answers: { type: "boolean" },
80
+ shuffle_questions: { type: "boolean" },
81
+ show_correct_answers: { type: "boolean" }
82
+ },
83
+ required: ["course_id", "quiz_id"],
84
+ },
85
+ },
86
+ handler: async (client, args) => {
87
+ const input = z.object({
88
+ course_id: z.union([z.number(), z.string()]),
89
+ quiz_id: z.string(),
90
+ title: z.string().optional(),
91
+ instructions: z.string().optional(),
92
+ due_at: z.string().optional(),
93
+ lock_at: z.string().optional(),
94
+ unlock_at: z.string().optional(),
95
+ points_possible: z.number().optional(),
96
+ time_limit: z.number().nullable().optional(),
97
+ allowed_attempts: z.number().optional(),
98
+ shuffle_answers: z.boolean().optional(),
99
+ shuffle_questions: z.boolean().optional(),
100
+ show_correct_answers: z.boolean().optional()
101
+ }).parse(args);
102
+ const courseId = await resolveCourseId(client, input.course_id);
103
+ const { course_id: _, quiz_id, ...updateData } = input;
104
+ const result = await client.updateNewQuiz(courseId, quiz_id, updateData);
105
+ return {
106
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
107
+ };
108
+ }
109
+ },
110
+ {
111
+ name: "canvas_delete_new_quiz",
112
+ tool: {
113
+ name: "canvas_delete_new_quiz",
114
+ description: "Delete a New Quiz (LTI) from a course",
115
+ inputSchema: {
116
+ type: "object",
117
+ properties: {
118
+ course_id: {
119
+ anyOf: [{ type: "number" }, { type: "string" }],
120
+ description: "The ID or name of the course"
121
+ },
122
+ quiz_id: { type: "string", description: "The New Quiz ID to delete" }
123
+ },
124
+ required: ["course_id", "quiz_id"],
125
+ },
126
+ },
127
+ handler: async (client, args) => {
128
+ const input = z.object({
129
+ course_id: z.union([z.number(), z.string()]),
130
+ quiz_id: z.string()
131
+ }).parse(args);
132
+ const courseId = await resolveCourseId(client, input.course_id);
133
+ const result = await client.deleteNewQuiz(courseId, input.quiz_id);
134
+ return {
135
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
136
+ };
137
+ }
138
+ },
139
+ {
140
+ name: "canvas_list_new_quiz_items",
141
+ tool: {
142
+ name: "canvas_list_new_quiz_items",
143
+ description: "List all questions/items in a New Quiz (LTI)",
144
+ inputSchema: {
145
+ type: "object",
146
+ properties: {
147
+ course_id: {
148
+ anyOf: [{ type: "number" }, { type: "string" }],
149
+ description: "The ID or name of the course"
150
+ },
151
+ quiz_id: { type: "string", description: "The New Quiz ID" }
152
+ },
153
+ required: ["course_id", "quiz_id"],
154
+ },
155
+ },
156
+ handler: async (client, args) => {
157
+ const input = z.object({
158
+ course_id: z.union([z.number(), z.string()]),
159
+ quiz_id: z.string()
160
+ }).parse(args);
161
+ const courseId = await resolveCourseId(client, input.course_id);
162
+ const result = await client.listNewQuizItems(courseId, input.quiz_id);
163
+ return {
164
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
165
+ };
166
+ }
167
+ },
168
+ {
169
+ name: "canvas_get_new_quiz_item",
170
+ tool: {
171
+ name: "canvas_get_new_quiz_item",
172
+ description: "Get details of a specific item/question in a New Quiz (LTI)",
173
+ inputSchema: {
174
+ type: "object",
175
+ properties: {
176
+ course_id: {
177
+ anyOf: [{ type: "number" }, { type: "string" }],
178
+ description: "The ID or name of the course"
179
+ },
180
+ quiz_id: { type: "string", description: "The New Quiz ID" },
181
+ item_id: { type: "string", description: "The item ID" }
182
+ },
183
+ required: ["course_id", "quiz_id", "item_id"],
184
+ },
185
+ },
186
+ handler: async (client, args) => {
187
+ const input = z.object({
188
+ course_id: z.union([z.number(), z.string()]),
189
+ quiz_id: z.string(),
190
+ item_id: z.string()
191
+ }).parse(args);
192
+ const courseId = await resolveCourseId(client, input.course_id);
193
+ const result = await client.getNewQuizItem(courseId, input.quiz_id, input.item_id);
194
+ return {
195
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
196
+ };
197
+ }
198
+ },
199
+ {
200
+ name: "canvas_create_new_quiz_item",
201
+ tool: {
202
+ name: "canvas_create_new_quiz_item",
203
+ description: "Add a question/item to a New Quiz (LTI). Supports multiple choice, true/false, essay, fill-in-blank, matching, and more.",
204
+ inputSchema: {
205
+ type: "object",
206
+ properties: {
207
+ course_id: {
208
+ anyOf: [{ type: "number" }, { type: "string" }],
209
+ description: "The ID or name of the course"
210
+ },
211
+ quiz_id: { type: "string", description: "The New Quiz ID" },
212
+ points_possible: { type: "number", description: "Points for this item (default: 1)" },
213
+ position: { type: "number", description: "Position order in the quiz" },
214
+ entry_type: {
215
+ type: "string",
216
+ description: "Always use 'Item' for a standard question"
217
+ },
218
+ title: { type: "string", description: "Question title/name" },
219
+ item_body: { type: "string", description: "HTML question text shown to students" },
220
+ interaction_type_slug: {
221
+ type: "string",
222
+ description: "Question type: choice (multiple choice), true-false, essay, short-answer, matching, ordering, file-upload, categorization, hot-spot"
223
+ },
224
+ interaction_data: {
225
+ type: "object",
226
+ description: "Question-type-specific data (choices, correct answers, etc.)"
227
+ },
228
+ scoring_data: {
229
+ type: "object",
230
+ description: "Scoring configuration for the question"
231
+ }
232
+ },
233
+ required: ["course_id", "quiz_id", "entry_type", "item_body", "interaction_type_slug"],
234
+ },
235
+ },
236
+ handler: async (client, args) => {
237
+ const input = z.object({
238
+ course_id: z.union([z.number(), z.string()]),
239
+ quiz_id: z.string(),
240
+ points_possible: z.number().optional(),
241
+ position: z.number().optional(),
242
+ entry_type: z.string(),
243
+ title: z.string().optional(),
244
+ item_body: z.string(),
245
+ interaction_type_slug: z.string(),
246
+ interaction_data: z.record(z.any()).optional(),
247
+ scoring_data: z.record(z.any()).optional()
248
+ }).parse(args);
249
+ const courseId = await resolveCourseId(client, input.course_id);
250
+ const result = await client.createNewQuizItem(courseId, input.quiz_id, {
251
+ position: input.position,
252
+ points_possible: input.points_possible,
253
+ entry_type: input.entry_type,
254
+ entry: {
255
+ title: input.title,
256
+ item_body: input.item_body,
257
+ interaction_type_slug: input.interaction_type_slug,
258
+ interaction_data: input.interaction_data,
259
+ scoring_data: input.scoring_data
260
+ }
261
+ });
262
+ return {
263
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
264
+ };
265
+ }
266
+ },
267
+ {
268
+ name: "canvas_update_new_quiz_item",
269
+ tool: {
270
+ name: "canvas_update_new_quiz_item",
271
+ description: "Update an existing question/item in a New Quiz (LTI)",
272
+ inputSchema: {
273
+ type: "object",
274
+ properties: {
275
+ course_id: {
276
+ anyOf: [{ type: "number" }, { type: "string" }],
277
+ description: "The ID or name of the course"
278
+ },
279
+ quiz_id: { type: "string", description: "The New Quiz ID" },
280
+ item_id: { type: "string", description: "The item ID to update" },
281
+ points_possible: { type: "number" },
282
+ position: { type: "number" },
283
+ title: { type: "string" },
284
+ item_body: { type: "string", description: "HTML question text" },
285
+ interaction_data: { type: "object" },
286
+ scoring_data: { type: "object" }
287
+ },
288
+ required: ["course_id", "quiz_id", "item_id"],
289
+ },
290
+ },
291
+ handler: async (client, args) => {
292
+ const input = z.object({
293
+ course_id: z.union([z.number(), z.string()]),
294
+ quiz_id: z.string(),
295
+ item_id: z.string(),
296
+ points_possible: z.number().optional(),
297
+ position: z.number().optional(),
298
+ title: z.string().optional(),
299
+ item_body: z.string().optional(),
300
+ interaction_data: z.record(z.any()).optional(),
301
+ scoring_data: z.record(z.any()).optional()
302
+ }).parse(args);
303
+ const courseId = await resolveCourseId(client, input.course_id);
304
+ const updatePayload = {};
305
+ if (input.points_possible !== undefined)
306
+ updatePayload.points_possible = input.points_possible;
307
+ if (input.position !== undefined)
308
+ updatePayload.position = input.position;
309
+ if (input.title || input.item_body || input.interaction_data || input.scoring_data) {
310
+ updatePayload.entry = {};
311
+ if (input.title)
312
+ updatePayload.entry.title = input.title;
313
+ if (input.item_body)
314
+ updatePayload.entry.item_body = input.item_body;
315
+ if (input.interaction_data)
316
+ updatePayload.entry.interaction_data = input.interaction_data;
317
+ if (input.scoring_data)
318
+ updatePayload.entry.scoring_data = input.scoring_data;
319
+ }
320
+ const result = await client.updateNewQuizItem(courseId, input.quiz_id, input.item_id, updatePayload);
321
+ return {
322
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
323
+ };
324
+ }
325
+ },
326
+ {
327
+ name: "canvas_delete_new_quiz_item",
328
+ tool: {
329
+ name: "canvas_delete_new_quiz_item",
330
+ description: "Delete a question/item from a New Quiz (LTI)",
331
+ inputSchema: {
332
+ type: "object",
333
+ properties: {
334
+ course_id: {
335
+ anyOf: [{ type: "number" }, { type: "string" }],
336
+ description: "The ID or name of the course"
337
+ },
338
+ quiz_id: { type: "string", description: "The New Quiz ID" },
339
+ item_id: { type: "string", description: "The item ID to delete" }
340
+ },
341
+ required: ["course_id", "quiz_id", "item_id"],
342
+ },
343
+ },
344
+ handler: async (client, args) => {
345
+ const input = z.object({
346
+ course_id: z.union([z.number(), z.string()]),
347
+ quiz_id: z.string(),
348
+ item_id: z.string()
349
+ }).parse(args);
350
+ const courseId = await resolveCourseId(client, input.course_id);
351
+ const result = await client.deleteNewQuizItem(courseId, input.quiz_id, input.item_id);
352
+ return {
353
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
354
+ };
355
+ }
356
+ }
357
+ ];
@@ -0,0 +1,130 @@
1
+ import { resolveCourseId } from "../common/helpers.js";
2
+ import { z } from "zod";
3
+ export const peerReviewTools = [
4
+ {
5
+ name: "canvas_list_peer_reviews",
6
+ tool: {
7
+ name: "canvas_list_peer_reviews",
8
+ description: "List all peer reviews assigned for an assignment",
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
+ assignment_id: { type: "number", description: "The ID of the assignment" }
17
+ },
18
+ required: ["course_id", "assignment_id"],
19
+ },
20
+ },
21
+ handler: async (client, args) => {
22
+ const input = z.object({
23
+ course_id: z.union([z.number(), z.string()]),
24
+ assignment_id: z.coerce.number()
25
+ }).parse(args);
26
+ const courseId = await resolveCourseId(client, input.course_id);
27
+ const result = await client.listPeerReviews(courseId, input.assignment_id);
28
+ return {
29
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
30
+ };
31
+ }
32
+ },
33
+ {
34
+ name: "canvas_get_submission_peer_reviews",
35
+ tool: {
36
+ name: "canvas_get_submission_peer_reviews",
37
+ description: "List peer reviews assigned to a specific student submission",
38
+ inputSchema: {
39
+ type: "object",
40
+ properties: {
41
+ course_id: {
42
+ anyOf: [{ type: "number" }, { type: "string" }],
43
+ description: "The ID or name of the course"
44
+ },
45
+ assignment_id: { type: "number", description: "The ID of the assignment" },
46
+ student_id: { type: "number", description: "The Canvas user ID of the student whose submission is being reviewed" }
47
+ },
48
+ required: ["course_id", "assignment_id", "student_id"],
49
+ },
50
+ },
51
+ handler: async (client, args) => {
52
+ const input = z.object({
53
+ course_id: z.union([z.number(), z.string()]),
54
+ assignment_id: z.coerce.number(),
55
+ student_id: z.coerce.number()
56
+ }).parse(args);
57
+ const courseId = await resolveCourseId(client, input.course_id);
58
+ const result = await client.getSubmissionPeerReviews(courseId, input.assignment_id, input.student_id);
59
+ return {
60
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
61
+ };
62
+ }
63
+ },
64
+ {
65
+ name: "canvas_create_peer_review",
66
+ tool: {
67
+ name: "canvas_create_peer_review",
68
+ description: "Manually assign a peer review: one student reviews another student's submission",
69
+ inputSchema: {
70
+ type: "object",
71
+ properties: {
72
+ course_id: {
73
+ anyOf: [{ type: "number" }, { type: "string" }],
74
+ description: "The ID or name of the course"
75
+ },
76
+ assignment_id: { type: "number", description: "The ID of the assignment" },
77
+ submission_student_id: { type: "number", description: "User ID of the student whose submission will be reviewed" },
78
+ reviewer_id: { type: "number", description: "User ID of the student who will perform the review" }
79
+ },
80
+ required: ["course_id", "assignment_id", "submission_student_id", "reviewer_id"],
81
+ },
82
+ },
83
+ handler: async (client, args) => {
84
+ const input = z.object({
85
+ course_id: z.union([z.number(), z.string()]),
86
+ assignment_id: z.coerce.number(),
87
+ submission_student_id: z.coerce.number(),
88
+ reviewer_id: z.coerce.number()
89
+ }).parse(args);
90
+ const courseId = await resolveCourseId(client, input.course_id);
91
+ const result = await client.createPeerReview(courseId, input.assignment_id, input.submission_student_id, input.reviewer_id);
92
+ return {
93
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
94
+ };
95
+ }
96
+ },
97
+ {
98
+ name: "canvas_delete_peer_review",
99
+ tool: {
100
+ name: "canvas_delete_peer_review",
101
+ description: "Remove a peer review assignment",
102
+ inputSchema: {
103
+ type: "object",
104
+ properties: {
105
+ course_id: {
106
+ anyOf: [{ type: "number" }, { type: "string" }],
107
+ description: "The ID or name of the course"
108
+ },
109
+ assignment_id: { type: "number", description: "The ID of the assignment" },
110
+ submission_student_id: { type: "number", description: "User ID of the student whose submission was being reviewed" },
111
+ reviewer_id: { type: "number", description: "User ID of the reviewer to remove" }
112
+ },
113
+ required: ["course_id", "assignment_id", "submission_student_id", "reviewer_id"],
114
+ },
115
+ },
116
+ handler: async (client, args) => {
117
+ const input = z.object({
118
+ course_id: z.union([z.number(), z.string()]),
119
+ assignment_id: z.coerce.number(),
120
+ submission_student_id: z.coerce.number(),
121
+ reviewer_id: z.coerce.number()
122
+ }).parse(args);
123
+ const courseId = await resolveCourseId(client, input.course_id);
124
+ const result = await client.deletePeerReview(courseId, input.assignment_id, input.submission_student_id, input.reviewer_id);
125
+ return {
126
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
127
+ };
128
+ }
129
+ }
130
+ ];