canvas-lms-mcp 1.3.0 → 1.4.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.
- package/dist/{chunk-VDHNHHYO.cjs → chunk-2BS2WOAF.cjs} +998 -909
- package/dist/chunk-2BS2WOAF.cjs.map +1 -0
- package/dist/{chunk-XSWWF7FN.js → chunk-LZ3KWP3F.js} +1097 -1008
- package/dist/chunk-LZ3KWP3F.js.map +1 -0
- package/dist/http.cjs +2 -2
- package/dist/http.js +1 -1
- package/dist/server.cjs +2 -2
- package/dist/server.js +1 -1
- package/dist/stdio.cjs +2 -2
- package/dist/stdio.js +1 -1
- package/package.json +3 -1
- package/dist/chunk-VDHNHHYO.cjs.map +0 -1
- package/dist/chunk-XSWWF7FN.js.map +0 -1
|
@@ -13,6 +13,104 @@ var _chunkXAOI3FO6cjs = require('./chunk-XAOI3FO6.cjs');
|
|
|
13
13
|
// src/server.ts
|
|
14
14
|
var _mcpjs = require('@modelcontextprotocol/sdk/server/mcp.js');
|
|
15
15
|
|
|
16
|
+
// src/tools/accounts.ts
|
|
17
|
+
var _zod = require('zod');
|
|
18
|
+
function accountTools(canvas) {
|
|
19
|
+
return [
|
|
20
|
+
{
|
|
21
|
+
name: "get_account",
|
|
22
|
+
description: "Get details for a Canvas account by ID.",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
account_id: _zod.z.number().describe("The Canvas account ID")
|
|
25
|
+
},
|
|
26
|
+
annotations: {
|
|
27
|
+
readOnlyHint: true,
|
|
28
|
+
openWorldHint: true
|
|
29
|
+
},
|
|
30
|
+
handler: async (params) => {
|
|
31
|
+
return canvas.accounts.get(params.account_id);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "list_accounts",
|
|
36
|
+
description: "List all accounts accessible to the authenticated user.",
|
|
37
|
+
inputSchema: {},
|
|
38
|
+
annotations: {
|
|
39
|
+
readOnlyHint: true,
|
|
40
|
+
openWorldHint: true
|
|
41
|
+
},
|
|
42
|
+
handler: async () => {
|
|
43
|
+
return canvas.accounts.list();
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "list_sub_accounts",
|
|
48
|
+
description: "List sub-accounts under a given Canvas account.",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
account_id: _zod.z.number().describe("The parent Canvas account ID")
|
|
51
|
+
},
|
|
52
|
+
annotations: {
|
|
53
|
+
readOnlyHint: true,
|
|
54
|
+
openWorldHint: true
|
|
55
|
+
},
|
|
56
|
+
handler: async (params) => {
|
|
57
|
+
return canvas.accounts.listSubAccounts(params.account_id);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "list_account_courses",
|
|
62
|
+
description: "List courses under a given Canvas account.",
|
|
63
|
+
inputSchema: {
|
|
64
|
+
account_id: _zod.z.number().describe("The Canvas account ID"),
|
|
65
|
+
search_term: _zod.z.string().optional().describe("Search courses by name or course code")
|
|
66
|
+
},
|
|
67
|
+
annotations: {
|
|
68
|
+
readOnlyHint: true,
|
|
69
|
+
openWorldHint: true
|
|
70
|
+
},
|
|
71
|
+
handler: async (params) => {
|
|
72
|
+
return canvas.accounts.listCourses(params.account_id, {
|
|
73
|
+
search_term: params.search_term
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: "list_account_users",
|
|
79
|
+
description: "List users in a Canvas account.",
|
|
80
|
+
inputSchema: {
|
|
81
|
+
account_id: _zod.z.number().describe("The Canvas account ID"),
|
|
82
|
+
search_term: _zod.z.string().optional().describe("Search users by name, email, or login")
|
|
83
|
+
},
|
|
84
|
+
annotations: {
|
|
85
|
+
readOnlyHint: true,
|
|
86
|
+
openWorldHint: true
|
|
87
|
+
},
|
|
88
|
+
handler: async (params) => {
|
|
89
|
+
return canvas.accounts.listUsers(params.account_id, {
|
|
90
|
+
search_term: params.search_term
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "get_account_reports",
|
|
96
|
+
description: "List available report types for a Canvas account.",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
account_id: _zod.z.number().describe("The Canvas account ID")
|
|
99
|
+
},
|
|
100
|
+
annotations: {
|
|
101
|
+
readOnlyHint: true,
|
|
102
|
+
openWorldHint: true
|
|
103
|
+
},
|
|
104
|
+
handler: async (params) => {
|
|
105
|
+
return canvas.accounts.getReports(params.account_id);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/tools/analytics.ts
|
|
112
|
+
|
|
113
|
+
|
|
16
114
|
// src/tools/errors.ts
|
|
17
115
|
function formatError(error) {
|
|
18
116
|
if (error instanceof _chunkXAOI3FO6cjs.CanvasApiError) {
|
|
@@ -50,47 +148,53 @@ function isNetworkError(error) {
|
|
|
50
148
|
return msg.includes("fetch") || msg.includes("enotfound") || msg.includes("econnrefused") || msg.includes("econnreset") || msg.includes("etimedout") || msg.includes("network") || msg.includes("dns") || msg.includes("socket") || error.name === "TypeError";
|
|
51
149
|
}
|
|
52
150
|
|
|
53
|
-
// src/tools/
|
|
54
|
-
function
|
|
55
|
-
return [
|
|
56
|
-
{
|
|
57
|
-
name: "health_check",
|
|
58
|
-
description: "Check if the Canvas API is reachable and the token is valid. Returns ok/error status.",
|
|
59
|
-
inputSchema: {},
|
|
60
|
-
annotations: {
|
|
61
|
-
readOnlyHint: true,
|
|
62
|
-
openWorldHint: true
|
|
63
|
-
},
|
|
64
|
-
handler: async () => {
|
|
65
|
-
await canvas.users.getProfile();
|
|
66
|
-
return { status: "ok", message: "Canvas API is reachable" };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// src/tools/courses.ts
|
|
73
|
-
var _zod = require('zod');
|
|
74
|
-
function courseTools(canvas) {
|
|
151
|
+
// src/tools/analytics.ts
|
|
152
|
+
function analyticsTools(canvas) {
|
|
75
153
|
return [
|
|
76
154
|
{
|
|
77
|
-
name: "
|
|
78
|
-
description: "
|
|
155
|
+
name: "search_course_content",
|
|
156
|
+
description: "Search for content within a course. Searches pages, assignments, discussions, and announcements by keyword.",
|
|
79
157
|
inputSchema: {
|
|
80
|
-
|
|
158
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
159
|
+
search_term: _zod.z.string().describe("The keyword or phrase to search for"),
|
|
160
|
+
content_types: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.SEARCH_CONTENT_TYPES)).optional().describe(
|
|
161
|
+
"Content types to search. Defaults to all types: pages, discussions, assignments, announcements."
|
|
162
|
+
)
|
|
81
163
|
},
|
|
82
164
|
annotations: {
|
|
83
165
|
readOnlyHint: true,
|
|
84
166
|
openWorldHint: true
|
|
85
167
|
},
|
|
86
168
|
handler: async (params) => {
|
|
87
|
-
const
|
|
88
|
-
|
|
169
|
+
const courseId = params.course_id;
|
|
170
|
+
const searchTerm = params.search_term;
|
|
171
|
+
const types = _nullishCoalesce(params.content_types, () => ( [
|
|
172
|
+
..._chunkXAOI3FO6cjs.SEARCH_CONTENT_TYPES
|
|
173
|
+
]));
|
|
174
|
+
if (types.length === 0) return { results: [] };
|
|
175
|
+
const settled = await Promise.allSettled(
|
|
176
|
+
types.map((type) => canvas.analytics.searchContentType(courseId, searchTerm, type))
|
|
177
|
+
);
|
|
178
|
+
const fulfilled = settled.filter(
|
|
179
|
+
(r) => r.status === "fulfilled"
|
|
180
|
+
);
|
|
181
|
+
if (fulfilled.length === 0) {
|
|
182
|
+
const allErrors = settled.map(
|
|
183
|
+
(result, index) => result.status === "rejected" ? `${types[index]}: ${formatError(result.reason)}` : null
|
|
184
|
+
).filter((errorLine) => errorLine !== null);
|
|
185
|
+
throw new Error(`All content type searches failed:
|
|
186
|
+
${allErrors.join("\n")}`);
|
|
187
|
+
}
|
|
188
|
+
const results = fulfilled.flatMap((r) => r.value);
|
|
189
|
+
const warnings = settled.map(
|
|
190
|
+
(r, i) => r.status === "rejected" ? `${types[i]} search failed: ${formatError(r.reason)}` : null
|
|
191
|
+
).filter((w) => w !== null);
|
|
192
|
+
return warnings.length > 0 ? { results, warnings } : { results };
|
|
89
193
|
}
|
|
90
194
|
},
|
|
91
195
|
{
|
|
92
|
-
name: "
|
|
93
|
-
description: "Get
|
|
196
|
+
name: "get_course_analytics",
|
|
197
|
+
description: "Get course-level activity analytics. Returns daily page view and participation counts.",
|
|
94
198
|
inputSchema: {
|
|
95
199
|
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
96
200
|
},
|
|
@@ -100,14 +204,15 @@ function courseTools(canvas) {
|
|
|
100
204
|
},
|
|
101
205
|
handler: async (params) => {
|
|
102
206
|
const course_id = params.course_id;
|
|
103
|
-
return canvas.
|
|
207
|
+
return canvas.analytics.getCourseActivity(course_id);
|
|
104
208
|
}
|
|
105
209
|
},
|
|
106
210
|
{
|
|
107
|
-
name: "
|
|
108
|
-
description: "Get
|
|
211
|
+
name: "get_student_analytics",
|
|
212
|
+
description: "Get per-student activity analytics for a course. Returns page views, participations, and submission timeline for a specific student.",
|
|
109
213
|
inputSchema: {
|
|
110
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
214
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
215
|
+
student_id: _zod.z.number().describe("The Canvas user ID of the student")
|
|
111
216
|
},
|
|
112
217
|
annotations: {
|
|
113
218
|
readOnlyHint: true,
|
|
@@ -115,49 +220,23 @@ function courseTools(canvas) {
|
|
|
115
220
|
},
|
|
116
221
|
handler: async (params) => {
|
|
117
222
|
const course_id = params.course_id;
|
|
118
|
-
const
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: "create_course",
|
|
124
|
-
description: "Create a new course in a Canvas account. Returns the created course object.",
|
|
125
|
-
inputSchema: {
|
|
126
|
-
account_id: _zod.z.number().int().positive().describe("The Canvas account ID to create the course in"),
|
|
127
|
-
name: _zod.z.string().describe("The name of the course"),
|
|
128
|
-
course_code: _zod.z.string().optional().describe("The course code (e.g. CS101)"),
|
|
129
|
-
start_at: _zod.z.string().datetime().optional().describe("Course start date in ISO 8601 format (e.g. 2026-01-15T00:00:00Z)"),
|
|
130
|
-
end_at: _zod.z.string().datetime().optional().describe("Course end date in ISO 8601 format (e.g. 2026-05-15T00:00:00Z)")
|
|
131
|
-
},
|
|
132
|
-
annotations: {
|
|
133
|
-
destructiveHint: true,
|
|
134
|
-
openWorldHint: true
|
|
135
|
-
},
|
|
136
|
-
handler: async (params) => {
|
|
137
|
-
const { account_id, ...courseFields } = params;
|
|
138
|
-
return canvas.courses.create({ account_id, ...courseFields });
|
|
223
|
+
const student_id = params.student_id;
|
|
224
|
+
return canvas.analytics.getStudentActivity(course_id, student_id);
|
|
139
225
|
}
|
|
140
226
|
},
|
|
141
227
|
{
|
|
142
|
-
name: "
|
|
143
|
-
description: "
|
|
228
|
+
name: "get_course_activity_stream",
|
|
229
|
+
description: "Get a summary of recent activity in a course. Returns counts of recent events grouped by type (submissions, discussions, announcements, etc.).",
|
|
144
230
|
inputSchema: {
|
|
145
|
-
course_id: _zod.z.number().
|
|
146
|
-
name: _zod.z.string().optional().describe("New course name"),
|
|
147
|
-
course_code: _zod.z.string().optional().describe("New course code"),
|
|
148
|
-
start_at: _zod.z.string().datetime().optional().describe("New start date in ISO 8601 format (e.g. 2026-01-15T00:00:00Z)"),
|
|
149
|
-
end_at: _zod.z.string().datetime().optional().describe("New end date in ISO 8601 format (e.g. 2026-05-15T00:00:00Z)"),
|
|
150
|
-
default_view: _zod.z.enum(["feed", "wiki", "modules", "assignments", "syllabus"]).optional().describe("Default course home page view"),
|
|
151
|
-
syllabus_body: _zod.z.string().optional().describe("HTML body for the course syllabus")
|
|
231
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
152
232
|
},
|
|
153
233
|
annotations: {
|
|
154
|
-
|
|
155
|
-
idempotentHint: true,
|
|
234
|
+
readOnlyHint: true,
|
|
156
235
|
openWorldHint: true
|
|
157
236
|
},
|
|
158
237
|
handler: async (params) => {
|
|
159
|
-
const
|
|
160
|
-
return canvas.
|
|
238
|
+
const course_id = params.course_id;
|
|
239
|
+
return canvas.analytics.getCourseActivityStream(course_id);
|
|
161
240
|
}
|
|
162
241
|
}
|
|
163
242
|
];
|
|
@@ -281,16 +360,15 @@ function assignmentTools(canvas) {
|
|
|
281
360
|
];
|
|
282
361
|
}
|
|
283
362
|
|
|
284
|
-
// src/tools/
|
|
363
|
+
// src/tools/calendar.ts
|
|
285
364
|
|
|
286
|
-
function
|
|
365
|
+
function calendarTools(canvas) {
|
|
287
366
|
return [
|
|
288
367
|
{
|
|
289
|
-
name: "
|
|
290
|
-
description: "List
|
|
368
|
+
name: "list_calendar_events",
|
|
369
|
+
description: "List calendar events for a course.",
|
|
291
370
|
inputSchema: {
|
|
292
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
293
|
-
assignment_id: _zod.z.number().describe("The Canvas assignment ID")
|
|
371
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
294
372
|
},
|
|
295
373
|
annotations: {
|
|
296
374
|
readOnlyHint: true,
|
|
@@ -298,201 +376,152 @@ function submissionTools(canvas) {
|
|
|
298
376
|
},
|
|
299
377
|
handler: async (params) => {
|
|
300
378
|
const course_id = params.course_id;
|
|
301
|
-
|
|
302
|
-
return canvas.submissions.list(course_id, assignment_id);
|
|
379
|
+
return canvas.calendar.list(course_id);
|
|
303
380
|
}
|
|
304
381
|
},
|
|
305
382
|
{
|
|
306
|
-
name: "
|
|
307
|
-
description: "
|
|
383
|
+
name: "create_calendar_event",
|
|
384
|
+
description: "Create a new calendar event in Canvas.",
|
|
308
385
|
inputSchema: {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
386
|
+
context_code: _zod.z.string().describe('Canvas context code, e.g. "course_123" for a course event'),
|
|
387
|
+
title: _zod.z.string().describe("Event title"),
|
|
388
|
+
start_at: _zod.z.string().describe('Start time in ISO 8601 format, e.g. "2026-05-01T10:00:00Z"'),
|
|
389
|
+
end_at: _zod.z.string().optional().describe("End time in ISO 8601 format. Omit for all-day events."),
|
|
390
|
+
description: _zod.z.string().optional().describe("Event description (HTML allowed)"),
|
|
391
|
+
location_name: _zod.z.string().optional().describe("Location name")
|
|
312
392
|
},
|
|
313
393
|
annotations: {
|
|
314
|
-
|
|
394
|
+
destructiveHint: true,
|
|
315
395
|
openWorldHint: true
|
|
316
396
|
},
|
|
317
397
|
handler: async (params) => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
398
|
+
return canvas.calendar.createEvent({
|
|
399
|
+
context_code: params.context_code,
|
|
400
|
+
title: params.title,
|
|
401
|
+
start_at: params.start_at,
|
|
402
|
+
end_at: params.end_at,
|
|
403
|
+
description: params.description,
|
|
404
|
+
location_name: params.location_name
|
|
405
|
+
});
|
|
322
406
|
}
|
|
323
407
|
},
|
|
324
408
|
{
|
|
325
|
-
name: "
|
|
326
|
-
description: "
|
|
327
|
-
inputSchema: {
|
|
328
|
-
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
329
|
-
assignment_id: _zod.z.number().describe("The Canvas assignment ID"),
|
|
330
|
-
user_id: _zod.z.number().describe("The Canvas user ID"),
|
|
331
|
-
grade: _zod.z.string().describe('The grade to assign (e.g. "95", "A", "pass")')
|
|
332
|
-
},
|
|
333
|
-
annotations: {
|
|
334
|
-
destructiveHint: true,
|
|
335
|
-
idempotentHint: true,
|
|
336
|
-
openWorldHint: true
|
|
337
|
-
},
|
|
338
|
-
handler: async (params) => {
|
|
339
|
-
const course_id = params.course_id;
|
|
340
|
-
const assignment_id = params.assignment_id;
|
|
341
|
-
const user_id = params.user_id;
|
|
342
|
-
const grade = params.grade;
|
|
343
|
-
return canvas.submissions.grade(course_id, assignment_id, user_id, grade);
|
|
344
|
-
}
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
name: "comment_on_submission",
|
|
348
|
-
description: "Add a text comment to a submission.",
|
|
409
|
+
name: "update_calendar_event",
|
|
410
|
+
description: "Update an existing calendar event. Only provided fields are changed.",
|
|
349
411
|
inputSchema: {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
412
|
+
event_id: _zod.z.number().describe("The Canvas calendar event ID"),
|
|
413
|
+
title: _zod.z.string().optional().describe("New event title"),
|
|
414
|
+
start_at: _zod.z.string().optional().describe("New start time in ISO 8601 format"),
|
|
415
|
+
end_at: _zod.z.string().optional().describe("New end time in ISO 8601 format"),
|
|
416
|
+
description: _zod.z.string().optional().describe("New description (HTML allowed)"),
|
|
417
|
+
location_name: _zod.z.string().optional().describe("New location name")
|
|
354
418
|
},
|
|
355
419
|
annotations: {
|
|
356
420
|
destructiveHint: true,
|
|
357
421
|
openWorldHint: true
|
|
358
422
|
},
|
|
359
423
|
handler: async (params) => {
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
424
|
+
const event_id = params.event_id;
|
|
425
|
+
return canvas.calendar.updateEvent(event_id, {
|
|
426
|
+
title: params.title,
|
|
427
|
+
start_at: params.start_at,
|
|
428
|
+
end_at: params.end_at,
|
|
429
|
+
description: params.description,
|
|
430
|
+
location_name: params.location_name
|
|
431
|
+
});
|
|
365
432
|
}
|
|
366
433
|
}
|
|
367
434
|
];
|
|
368
435
|
}
|
|
369
436
|
|
|
370
|
-
// src/tools/
|
|
437
|
+
// src/tools/conversations.ts
|
|
371
438
|
|
|
372
|
-
function
|
|
439
|
+
function conversationTools(canvas) {
|
|
373
440
|
return [
|
|
374
441
|
{
|
|
375
|
-
name: "
|
|
376
|
-
description: "List
|
|
377
|
-
inputSchema: {
|
|
378
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
379
|
-
},
|
|
442
|
+
name: "list_conversations",
|
|
443
|
+
description: "List conversations (inbox messages) for the authenticated user.",
|
|
444
|
+
inputSchema: {},
|
|
380
445
|
annotations: {
|
|
381
446
|
readOnlyHint: true,
|
|
382
447
|
openWorldHint: true
|
|
383
448
|
},
|
|
384
|
-
handler: async (
|
|
385
|
-
|
|
386
|
-
return canvas.rubrics.list(course_id);
|
|
449
|
+
handler: async () => {
|
|
450
|
+
return canvas.conversations.list();
|
|
387
451
|
}
|
|
388
452
|
},
|
|
389
453
|
{
|
|
390
|
-
name: "
|
|
391
|
-
description: "Get
|
|
454
|
+
name: "get_conversation",
|
|
455
|
+
description: "Get a single conversation with its full message thread.",
|
|
392
456
|
inputSchema: {
|
|
393
|
-
|
|
394
|
-
rubric_id: _zod.z.number().describe("The Canvas rubric ID")
|
|
457
|
+
conversation_id: _zod.z.number().describe("The conversation ID")
|
|
395
458
|
},
|
|
396
459
|
annotations: {
|
|
397
460
|
readOnlyHint: true,
|
|
398
461
|
openWorldHint: true
|
|
399
462
|
},
|
|
400
463
|
handler: async (params) => {
|
|
401
|
-
|
|
402
|
-
const rubric_id = params.rubric_id;
|
|
403
|
-
return canvas.rubrics.get(course_id, rubric_id);
|
|
464
|
+
return canvas.conversations.get(params.conversation_id);
|
|
404
465
|
}
|
|
405
466
|
},
|
|
406
467
|
{
|
|
407
|
-
name: "
|
|
408
|
-
description: "Get the
|
|
409
|
-
inputSchema: {
|
|
410
|
-
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
411
|
-
assignment_id: _zod.z.number().describe("The Canvas assignment ID"),
|
|
412
|
-
user_id: _zod.z.number().describe("The Canvas user ID")
|
|
413
|
-
},
|
|
468
|
+
name: "get_conversation_unread_count",
|
|
469
|
+
description: "Get the number of unread conversations for the authenticated user.",
|
|
470
|
+
inputSchema: {},
|
|
414
471
|
annotations: {
|
|
415
472
|
readOnlyHint: true,
|
|
416
473
|
openWorldHint: true
|
|
417
474
|
},
|
|
418
|
-
handler: async (
|
|
419
|
-
|
|
420
|
-
const assignment_id = params.assignment_id;
|
|
421
|
-
const user_id = params.user_id;
|
|
422
|
-
return canvas.rubrics.getAssessment(course_id, assignment_id, user_id);
|
|
475
|
+
handler: async () => {
|
|
476
|
+
return canvas.conversations.getUnreadCount();
|
|
423
477
|
}
|
|
424
478
|
},
|
|
425
479
|
{
|
|
426
|
-
name: "
|
|
427
|
-
description: "
|
|
480
|
+
name: "send_conversation",
|
|
481
|
+
description: "Send a new conversation message to one or more recipients.",
|
|
428
482
|
inputSchema: {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
_zod.z.object({
|
|
433
|
-
criterion_id: _zod.z.string().describe("The rubric criterion ID"),
|
|
434
|
-
points: _zod.z.number().describe("Points awarded for this criterion"),
|
|
435
|
-
comments: _zod.z.string().describe("Feedback comment for this criterion")
|
|
436
|
-
})
|
|
437
|
-
).describe("Array of criterion assessments")
|
|
483
|
+
recipients: _zod.z.array(_zod.z.string()).describe("Array of recipient user IDs (as strings)"),
|
|
484
|
+
subject: _zod.z.string().describe("The conversation subject line"),
|
|
485
|
+
body: _zod.z.string().describe("The message body")
|
|
438
486
|
},
|
|
439
487
|
annotations: {
|
|
440
488
|
destructiveHint: true,
|
|
441
|
-
idempotentHint: true,
|
|
442
489
|
openWorldHint: true
|
|
443
490
|
},
|
|
444
491
|
handler: async (params) => {
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
return canvas.
|
|
492
|
+
const recipients = params.recipients;
|
|
493
|
+
const subject = params.subject;
|
|
494
|
+
const body = params.body;
|
|
495
|
+
return canvas.conversations.send(recipients, subject, body);
|
|
449
496
|
}
|
|
450
497
|
}
|
|
451
498
|
];
|
|
452
499
|
}
|
|
453
500
|
|
|
454
|
-
// src/tools/
|
|
501
|
+
// src/tools/courses.ts
|
|
455
502
|
|
|
456
|
-
function
|
|
503
|
+
function courseTools(canvas) {
|
|
457
504
|
return [
|
|
458
505
|
{
|
|
459
|
-
name: "
|
|
460
|
-
description: "List
|
|
461
|
-
inputSchema: {
|
|
462
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
463
|
-
},
|
|
464
|
-
annotations: {
|
|
465
|
-
readOnlyHint: true,
|
|
466
|
-
openWorldHint: true
|
|
467
|
-
},
|
|
468
|
-
handler: async (params) => {
|
|
469
|
-
const course_id = params.course_id;
|
|
470
|
-
return canvas.quizzes.list(course_id);
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
{
|
|
474
|
-
name: "get_quiz",
|
|
475
|
-
description: "Get details for a single quiz by ID.",
|
|
506
|
+
name: "list_courses",
|
|
507
|
+
description: "List courses for the authenticated user. Optionally filter by enrollment state.",
|
|
476
508
|
inputSchema: {
|
|
477
|
-
|
|
478
|
-
quiz_id: _zod.z.number().describe("The Canvas quiz ID")
|
|
509
|
+
enrollment_state: _zod.z.enum(["active", "completed", "all"]).optional().describe("Filter courses by enrollment state")
|
|
479
510
|
},
|
|
480
511
|
annotations: {
|
|
481
512
|
readOnlyHint: true,
|
|
482
513
|
openWorldHint: true
|
|
483
514
|
},
|
|
484
515
|
handler: async (params) => {
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
return canvas.quizzes.get(course_id, quiz_id);
|
|
516
|
+
const enrollment_state = params.enrollment_state;
|
|
517
|
+
return canvas.courses.list({ enrollment_state });
|
|
488
518
|
}
|
|
489
519
|
},
|
|
490
520
|
{
|
|
491
|
-
name: "
|
|
492
|
-
description: "
|
|
521
|
+
name: "get_course",
|
|
522
|
+
description: "Get details for a single course by ID, including term and total student count.",
|
|
493
523
|
inputSchema: {
|
|
494
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
495
|
-
quiz_id: _zod.z.number().describe("The Canvas quiz ID")
|
|
524
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
496
525
|
},
|
|
497
526
|
annotations: {
|
|
498
527
|
readOnlyHint: true,
|
|
@@ -500,16 +529,14 @@ function quizTools(canvas) {
|
|
|
500
529
|
},
|
|
501
530
|
handler: async (params) => {
|
|
502
531
|
const course_id = params.course_id;
|
|
503
|
-
|
|
504
|
-
return canvas.quizzes.listSubmissions(course_id, quiz_id);
|
|
532
|
+
return canvas.courses.get(course_id);
|
|
505
533
|
}
|
|
506
534
|
},
|
|
507
535
|
{
|
|
508
|
-
name: "
|
|
509
|
-
description: "
|
|
536
|
+
name: "get_syllabus",
|
|
537
|
+
description: "Get the syllabus HTML body for a course.",
|
|
510
538
|
inputSchema: {
|
|
511
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
512
|
-
quiz_id: _zod.z.number().describe("The Canvas quiz ID")
|
|
539
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
513
540
|
},
|
|
514
541
|
annotations: {
|
|
515
542
|
readOnlyHint: true,
|
|
@@ -517,36 +544,40 @@ function quizTools(canvas) {
|
|
|
517
544
|
},
|
|
518
545
|
handler: async (params) => {
|
|
519
546
|
const course_id = params.course_id;
|
|
520
|
-
const
|
|
521
|
-
return
|
|
547
|
+
const syllabus_body = await canvas.courses.getSyllabus(course_id);
|
|
548
|
+
return { course_id, syllabus_body };
|
|
522
549
|
}
|
|
523
550
|
},
|
|
524
551
|
{
|
|
525
|
-
name: "
|
|
526
|
-
description: "
|
|
552
|
+
name: "create_course",
|
|
553
|
+
description: "Create a new course in a Canvas account. Returns the created course object.",
|
|
527
554
|
inputSchema: {
|
|
528
|
-
|
|
555
|
+
account_id: _zod.z.number().int().positive().describe("The Canvas account ID to create the course in"),
|
|
556
|
+
name: _zod.z.string().describe("The name of the course"),
|
|
557
|
+
course_code: _zod.z.string().optional().describe("The course code (e.g. CS101)"),
|
|
558
|
+
start_at: _zod.z.string().datetime().optional().describe("Course start date in ISO 8601 format (e.g. 2026-01-15T00:00:00Z)"),
|
|
559
|
+
end_at: _zod.z.string().datetime().optional().describe("Course end date in ISO 8601 format (e.g. 2026-05-15T00:00:00Z)")
|
|
529
560
|
},
|
|
530
561
|
annotations: {
|
|
531
|
-
|
|
562
|
+
destructiveHint: true,
|
|
532
563
|
openWorldHint: true
|
|
533
564
|
},
|
|
534
565
|
handler: async (params) => {
|
|
535
|
-
const
|
|
536
|
-
return canvas.
|
|
566
|
+
const { account_id, ...courseFields } = params;
|
|
567
|
+
return canvas.courses.create({ account_id, ...courseFields });
|
|
537
568
|
}
|
|
538
569
|
},
|
|
539
570
|
{
|
|
540
|
-
name: "
|
|
541
|
-
description: "
|
|
571
|
+
name: "update_course",
|
|
572
|
+
description: "Update an existing course. Only provided fields are changed; omitted fields are left as-is.",
|
|
542
573
|
inputSchema: {
|
|
543
|
-
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
574
|
+
course_id: _zod.z.number().int().positive().describe("The Canvas course ID to update"),
|
|
575
|
+
name: _zod.z.string().optional().describe("New course name"),
|
|
576
|
+
course_code: _zod.z.string().optional().describe("New course code"),
|
|
577
|
+
start_at: _zod.z.string().datetime().optional().describe("New start date in ISO 8601 format (e.g. 2026-01-15T00:00:00Z)"),
|
|
578
|
+
end_at: _zod.z.string().datetime().optional().describe("New end date in ISO 8601 format (e.g. 2026-05-15T00:00:00Z)"),
|
|
579
|
+
default_view: _zod.z.enum(["feed", "wiki", "modules", "assignments", "syllabus"]).optional().describe("Default course home page view"),
|
|
580
|
+
syllabus_body: _zod.z.string().optional().describe("HTML body for the course syllabus")
|
|
550
581
|
},
|
|
551
582
|
annotations: {
|
|
552
583
|
destructiveHint: true,
|
|
@@ -554,127 +585,74 @@ function quizTools(canvas) {
|
|
|
554
585
|
openWorldHint: true
|
|
555
586
|
},
|
|
556
587
|
handler: async (params) => {
|
|
557
|
-
const course_id = params
|
|
558
|
-
|
|
559
|
-
const submission_id = params.submission_id;
|
|
560
|
-
const question_id = params.question_id;
|
|
561
|
-
const score = params.score;
|
|
562
|
-
const comment = params.comment;
|
|
563
|
-
const attempt = params.attempt;
|
|
564
|
-
await canvas.quizzes.scoreQuestion(
|
|
565
|
-
course_id,
|
|
566
|
-
quiz_id,
|
|
567
|
-
submission_id,
|
|
568
|
-
question_id,
|
|
569
|
-
score,
|
|
570
|
-
comment,
|
|
571
|
-
attempt
|
|
572
|
-
);
|
|
573
|
-
return { success: true };
|
|
588
|
+
const { course_id, ...fields } = params;
|
|
589
|
+
return canvas.courses.update(course_id, fields);
|
|
574
590
|
}
|
|
575
591
|
}
|
|
576
592
|
];
|
|
577
593
|
}
|
|
578
594
|
|
|
579
|
-
// src/tools/
|
|
580
|
-
|
|
581
|
-
function fileTools(canvas) {
|
|
595
|
+
// src/tools/dashboard.ts
|
|
596
|
+
function dashboardTools(canvas) {
|
|
582
597
|
return [
|
|
583
598
|
{
|
|
584
|
-
name: "
|
|
585
|
-
description: "
|
|
586
|
-
inputSchema: {
|
|
587
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
588
|
-
},
|
|
599
|
+
name: "get_dashboard_cards",
|
|
600
|
+
description: "Get the current user's dashboard course cards with position, color, and image.",
|
|
601
|
+
inputSchema: {},
|
|
589
602
|
annotations: {
|
|
590
603
|
readOnlyHint: true,
|
|
591
604
|
openWorldHint: true
|
|
592
605
|
},
|
|
593
|
-
handler: async (
|
|
594
|
-
|
|
595
|
-
return canvas.files.list(course_id);
|
|
606
|
+
handler: async () => {
|
|
607
|
+
return canvas.dashboard.getDashboardCards();
|
|
596
608
|
}
|
|
597
609
|
},
|
|
598
610
|
{
|
|
599
|
-
name: "
|
|
600
|
-
description: "
|
|
601
|
-
inputSchema: {
|
|
602
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
603
|
-
},
|
|
611
|
+
name: "get_todo_items",
|
|
612
|
+
description: "Get the current user's to-do items, including upcoming assignments and grading tasks.",
|
|
613
|
+
inputSchema: {},
|
|
604
614
|
annotations: {
|
|
605
615
|
readOnlyHint: true,
|
|
606
616
|
openWorldHint: true
|
|
607
617
|
},
|
|
608
|
-
handler: async (
|
|
609
|
-
|
|
610
|
-
return canvas.files.listFolders(course_id);
|
|
618
|
+
handler: async () => {
|
|
619
|
+
return canvas.dashboard.getTodoItems();
|
|
611
620
|
}
|
|
612
621
|
},
|
|
613
622
|
{
|
|
614
|
-
name: "
|
|
615
|
-
description: "Get
|
|
616
|
-
inputSchema: {
|
|
617
|
-
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
618
|
-
file_id: _zod.z.number().describe("The Canvas file ID")
|
|
619
|
-
},
|
|
623
|
+
name: "get_upcoming_events",
|
|
624
|
+
description: "Get the current user's upcoming calendar events and assignments.",
|
|
625
|
+
inputSchema: {},
|
|
620
626
|
annotations: {
|
|
621
627
|
readOnlyHint: true,
|
|
622
628
|
openWorldHint: true
|
|
623
629
|
},
|
|
624
|
-
handler: async (
|
|
625
|
-
|
|
626
|
-
const file_id = params.file_id;
|
|
627
|
-
return canvas.files.get(course_id, file_id);
|
|
628
|
-
}
|
|
629
|
-
},
|
|
630
|
-
{
|
|
631
|
-
name: "upload_file",
|
|
632
|
-
description: "Upload a file to a course. Content must be base64-encoded. Canvas performs a multi-step upload internally.",
|
|
633
|
-
inputSchema: {
|
|
634
|
-
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
635
|
-
name: _zod.z.string().describe("File name including extension"),
|
|
636
|
-
content: _zod.z.string().describe("Base64-encoded file content"),
|
|
637
|
-
content_type: _zod.z.string().describe('MIME type, e.g. "application/pdf" or "image/png"'),
|
|
638
|
-
parent_folder_path: _zod.z.string().optional().describe('Destination folder path within the course, e.g. "subfolder/nested"')
|
|
639
|
-
},
|
|
640
|
-
annotations: {
|
|
641
|
-
destructiveHint: true,
|
|
642
|
-
openWorldHint: true
|
|
643
|
-
},
|
|
644
|
-
handler: async (params) => {
|
|
645
|
-
const course_id = params.course_id;
|
|
646
|
-
const name = params.name;
|
|
647
|
-
const content = params.content;
|
|
648
|
-
const content_type = params.content_type;
|
|
649
|
-
const parent_folder_path = params.parent_folder_path;
|
|
650
|
-
return canvas.files.upload(course_id, name, content, content_type, parent_folder_path);
|
|
630
|
+
handler: async () => {
|
|
631
|
+
return canvas.dashboard.getUpcomingEvents();
|
|
651
632
|
}
|
|
652
633
|
},
|
|
653
634
|
{
|
|
654
|
-
name: "
|
|
655
|
-
description: "
|
|
656
|
-
inputSchema: {
|
|
657
|
-
file_id: _zod.z.number().describe("The Canvas file ID")
|
|
658
|
-
},
|
|
635
|
+
name: "get_missing_submissions",
|
|
636
|
+
description: "Get assignments with missing submissions for the current user.",
|
|
637
|
+
inputSchema: {},
|
|
659
638
|
annotations: {
|
|
660
|
-
|
|
639
|
+
readOnlyHint: true,
|
|
661
640
|
openWorldHint: true
|
|
662
641
|
},
|
|
663
|
-
handler: async (
|
|
664
|
-
|
|
665
|
-
return canvas.files.delete(file_id);
|
|
642
|
+
handler: async () => {
|
|
643
|
+
return canvas.dashboard.getMissingSubmissions();
|
|
666
644
|
}
|
|
667
645
|
}
|
|
668
646
|
];
|
|
669
647
|
}
|
|
670
648
|
|
|
671
|
-
// src/tools/
|
|
649
|
+
// src/tools/discussions.ts
|
|
672
650
|
|
|
673
|
-
function
|
|
651
|
+
function discussionTools(canvas) {
|
|
674
652
|
return [
|
|
675
653
|
{
|
|
676
|
-
name: "
|
|
677
|
-
description: "List all
|
|
654
|
+
name: "list_discussions",
|
|
655
|
+
description: "List all discussion topics in a course.",
|
|
678
656
|
inputSchema: {
|
|
679
657
|
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
680
658
|
},
|
|
@@ -684,111 +662,132 @@ function userTools(canvas) {
|
|
|
684
662
|
},
|
|
685
663
|
handler: async (params) => {
|
|
686
664
|
const course_id = params.course_id;
|
|
687
|
-
return canvas.
|
|
665
|
+
return canvas.discussions.list(course_id);
|
|
688
666
|
}
|
|
689
667
|
},
|
|
690
668
|
{
|
|
691
|
-
name: "
|
|
692
|
-
description: "Get details for a single
|
|
669
|
+
name: "get_discussion",
|
|
670
|
+
description: "Get details for a single discussion topic by ID.",
|
|
693
671
|
inputSchema: {
|
|
694
|
-
|
|
672
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
673
|
+
topic_id: _zod.z.number().describe("The Canvas discussion topic ID")
|
|
695
674
|
},
|
|
696
675
|
annotations: {
|
|
697
676
|
readOnlyHint: true,
|
|
698
677
|
openWorldHint: true
|
|
699
678
|
},
|
|
700
679
|
handler: async (params) => {
|
|
701
|
-
const
|
|
702
|
-
|
|
680
|
+
const course_id = params.course_id;
|
|
681
|
+
const topic_id = params.topic_id;
|
|
682
|
+
return canvas.discussions.get(course_id, topic_id);
|
|
703
683
|
}
|
|
704
684
|
},
|
|
705
685
|
{
|
|
706
|
-
name: "
|
|
707
|
-
description: "
|
|
708
|
-
inputSchema: {
|
|
686
|
+
name: "list_announcements",
|
|
687
|
+
description: "List all announcements in a course.",
|
|
688
|
+
inputSchema: {
|
|
689
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
690
|
+
},
|
|
709
691
|
annotations: {
|
|
710
692
|
readOnlyHint: true,
|
|
711
693
|
openWorldHint: true
|
|
712
694
|
},
|
|
713
|
-
handler: async () => {
|
|
714
|
-
|
|
695
|
+
handler: async (params) => {
|
|
696
|
+
const course_id = params.course_id;
|
|
697
|
+
return canvas.discussions.listAnnouncements(course_id);
|
|
715
698
|
}
|
|
716
699
|
},
|
|
717
700
|
{
|
|
718
|
-
name: "
|
|
719
|
-
description: "
|
|
701
|
+
name: "post_discussion_entry",
|
|
702
|
+
description: "Post a new entry (reply) to a discussion topic.",
|
|
720
703
|
inputSchema: {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
order: _zod.z.enum(["asc", "desc"]).optional().describe("Sort order")
|
|
704
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
705
|
+
topic_id: _zod.z.number().describe("The Canvas discussion topic ID"),
|
|
706
|
+
message: _zod.z.string().describe("The message body (supports HTML)")
|
|
725
707
|
},
|
|
726
708
|
annotations: {
|
|
727
|
-
|
|
709
|
+
destructiveHint: true,
|
|
728
710
|
openWorldHint: true
|
|
729
711
|
},
|
|
730
712
|
handler: async (params) => {
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
params.order
|
|
736
|
-
);
|
|
713
|
+
const course_id = params.course_id;
|
|
714
|
+
const topic_id = params.topic_id;
|
|
715
|
+
const message = params.message;
|
|
716
|
+
return canvas.discussions.postEntry(course_id, topic_id, message);
|
|
737
717
|
}
|
|
738
718
|
},
|
|
739
719
|
{
|
|
740
|
-
name: "
|
|
741
|
-
description: "
|
|
720
|
+
name: "create_discussion",
|
|
721
|
+
description: "Create a new discussion topic in a course.",
|
|
742
722
|
inputSchema: {
|
|
743
723
|
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
744
|
-
|
|
724
|
+
title: _zod.z.string().min(1).describe("Title of the discussion topic"),
|
|
725
|
+
message: _zod.z.string().optional().describe("Body text of the discussion (supports HTML)"),
|
|
726
|
+
discussion_type: _zod.z.enum(["side_comment", "threaded"]).optional().describe("Discussion type: side_comment (flat) or threaded"),
|
|
727
|
+
published: _zod.z.boolean().optional().describe("Whether the topic is published"),
|
|
728
|
+
require_initial_post: _zod.z.boolean().optional().describe("Require students to post before seeing replies")
|
|
745
729
|
},
|
|
746
730
|
annotations: {
|
|
747
|
-
|
|
731
|
+
destructiveHint: true,
|
|
748
732
|
openWorldHint: true
|
|
749
733
|
},
|
|
750
734
|
handler: async (params) => {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
params.
|
|
754
|
-
|
|
735
|
+
const course_id = params.course_id;
|
|
736
|
+
return canvas.discussions.create(course_id, {
|
|
737
|
+
title: params.title,
|
|
738
|
+
message: params.message,
|
|
739
|
+
discussion_type: params.discussion_type,
|
|
740
|
+
published: params.published,
|
|
741
|
+
require_initial_post: params.require_initial_post
|
|
742
|
+
});
|
|
755
743
|
}
|
|
756
|
-
}
|
|
757
|
-
];
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// src/tools/groups.ts
|
|
761
|
-
|
|
762
|
-
function groupTools(canvas) {
|
|
763
|
-
return [
|
|
744
|
+
},
|
|
764
745
|
{
|
|
765
|
-
name: "
|
|
766
|
-
description: "
|
|
746
|
+
name: "update_discussion",
|
|
747
|
+
description: "Update an existing discussion topic.",
|
|
767
748
|
inputSchema: {
|
|
768
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
749
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
750
|
+
topic_id: _zod.z.number().describe("The Canvas discussion topic ID"),
|
|
751
|
+
title: _zod.z.string().optional().describe("New title for the discussion topic"),
|
|
752
|
+
message: _zod.z.string().optional().describe("New body text (supports HTML)"),
|
|
753
|
+
published: _zod.z.boolean().optional().describe("Publish or unpublish the topic"),
|
|
754
|
+
require_initial_post: _zod.z.boolean().optional().describe("Require students to post before seeing replies")
|
|
769
755
|
},
|
|
770
756
|
annotations: {
|
|
771
|
-
|
|
757
|
+
destructiveHint: true,
|
|
772
758
|
openWorldHint: true
|
|
773
759
|
},
|
|
774
760
|
handler: async (params) => {
|
|
775
761
|
const course_id = params.course_id;
|
|
776
|
-
|
|
762
|
+
const topic_id = params.topic_id;
|
|
763
|
+
const updateParams = {
|
|
764
|
+
title: params.title,
|
|
765
|
+
message: params.message,
|
|
766
|
+
published: params.published,
|
|
767
|
+
require_initial_post: params.require_initial_post
|
|
768
|
+
};
|
|
769
|
+
if (Object.values(updateParams).every((v) => v === void 0)) {
|
|
770
|
+
throw new Error("At least one field must be provided to update a discussion topic");
|
|
771
|
+
}
|
|
772
|
+
return canvas.discussions.update(course_id, topic_id, updateParams);
|
|
777
773
|
}
|
|
778
774
|
},
|
|
779
775
|
{
|
|
780
|
-
name: "
|
|
781
|
-
description: "
|
|
776
|
+
name: "delete_discussion",
|
|
777
|
+
description: "Delete a discussion topic from a course.",
|
|
782
778
|
inputSchema: {
|
|
783
|
-
|
|
779
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
780
|
+
topic_id: _zod.z.number().describe("The Canvas discussion topic ID to delete")
|
|
784
781
|
},
|
|
785
782
|
annotations: {
|
|
786
|
-
|
|
783
|
+
destructiveHint: true,
|
|
787
784
|
openWorldHint: true
|
|
788
785
|
},
|
|
789
786
|
handler: async (params) => {
|
|
790
|
-
const
|
|
791
|
-
|
|
787
|
+
const course_id = params.course_id;
|
|
788
|
+
const topic_id = params.topic_id;
|
|
789
|
+
await canvas.discussions.delete(course_id, topic_id);
|
|
790
|
+
return { deleted: true, topic_id };
|
|
792
791
|
}
|
|
793
792
|
}
|
|
794
793
|
];
|
|
@@ -861,13 +860,13 @@ function enrollmentTools(canvas) {
|
|
|
861
860
|
];
|
|
862
861
|
}
|
|
863
862
|
|
|
864
|
-
// src/tools/
|
|
863
|
+
// src/tools/files.ts
|
|
865
864
|
|
|
866
|
-
function
|
|
865
|
+
function fileTools(canvas) {
|
|
867
866
|
return [
|
|
868
867
|
{
|
|
869
|
-
name: "
|
|
870
|
-
description: "List all
|
|
868
|
+
name: "list_files",
|
|
869
|
+
description: "List all files in a course.",
|
|
871
870
|
inputSchema: {
|
|
872
871
|
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
873
872
|
},
|
|
@@ -877,15 +876,14 @@ function discussionTools(canvas) {
|
|
|
877
876
|
},
|
|
878
877
|
handler: async (params) => {
|
|
879
878
|
const course_id = params.course_id;
|
|
880
|
-
return canvas.
|
|
879
|
+
return canvas.files.list(course_id);
|
|
881
880
|
}
|
|
882
881
|
},
|
|
883
882
|
{
|
|
884
|
-
name: "
|
|
885
|
-
description: "
|
|
883
|
+
name: "list_folders",
|
|
884
|
+
description: "List all folders in a course.",
|
|
886
885
|
inputSchema: {
|
|
887
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
888
|
-
topic_id: _zod.z.number().describe("The Canvas discussion topic ID")
|
|
886
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
889
887
|
},
|
|
890
888
|
annotations: {
|
|
891
889
|
readOnlyHint: true,
|
|
@@ -893,15 +891,15 @@ function discussionTools(canvas) {
|
|
|
893
891
|
},
|
|
894
892
|
handler: async (params) => {
|
|
895
893
|
const course_id = params.course_id;
|
|
896
|
-
|
|
897
|
-
return canvas.discussions.get(course_id, topic_id);
|
|
894
|
+
return canvas.files.listFolders(course_id);
|
|
898
895
|
}
|
|
899
896
|
},
|
|
900
897
|
{
|
|
901
|
-
name: "
|
|
902
|
-
description: "
|
|
898
|
+
name: "get_file",
|
|
899
|
+
description: "Get metadata for a single file by ID, including download URL.",
|
|
903
900
|
inputSchema: {
|
|
904
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
901
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
902
|
+
file_id: _zod.z.number().describe("The Canvas file ID")
|
|
905
903
|
},
|
|
906
904
|
annotations: {
|
|
907
905
|
readOnlyHint: true,
|
|
@@ -909,16 +907,19 @@ function discussionTools(canvas) {
|
|
|
909
907
|
},
|
|
910
908
|
handler: async (params) => {
|
|
911
909
|
const course_id = params.course_id;
|
|
912
|
-
|
|
910
|
+
const file_id = params.file_id;
|
|
911
|
+
return canvas.files.get(course_id, file_id);
|
|
913
912
|
}
|
|
914
913
|
},
|
|
915
914
|
{
|
|
916
|
-
name: "
|
|
917
|
-
description: "
|
|
915
|
+
name: "upload_file",
|
|
916
|
+
description: "Upload a file to a course. Content must be base64-encoded. Canvas performs a multi-step upload internally.",
|
|
918
917
|
inputSchema: {
|
|
919
918
|
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
920
|
-
|
|
921
|
-
|
|
919
|
+
name: _zod.z.string().describe("File name including extension"),
|
|
920
|
+
content: _zod.z.string().describe("Base64-encoded file content"),
|
|
921
|
+
content_type: _zod.z.string().describe('MIME type, e.g. "application/pdf" or "image/png"'),
|
|
922
|
+
parent_folder_path: _zod.z.string().optional().describe('Destination folder path within the course, e.g. "subfolder/nested"')
|
|
922
923
|
},
|
|
923
924
|
annotations: {
|
|
924
925
|
destructiveHint: true,
|
|
@@ -926,83 +927,82 @@ function discussionTools(canvas) {
|
|
|
926
927
|
},
|
|
927
928
|
handler: async (params) => {
|
|
928
929
|
const course_id = params.course_id;
|
|
929
|
-
const
|
|
930
|
-
const
|
|
931
|
-
|
|
930
|
+
const name = params.name;
|
|
931
|
+
const content = params.content;
|
|
932
|
+
const content_type = params.content_type;
|
|
933
|
+
const parent_folder_path = params.parent_folder_path;
|
|
934
|
+
return canvas.files.upload(course_id, name, content, content_type, parent_folder_path);
|
|
932
935
|
}
|
|
933
936
|
},
|
|
934
937
|
{
|
|
935
|
-
name: "
|
|
936
|
-
description: "
|
|
938
|
+
name: "delete_file",
|
|
939
|
+
description: "Delete a file by ID. This action is permanent.",
|
|
937
940
|
inputSchema: {
|
|
938
|
-
|
|
939
|
-
title: _zod.z.string().min(1).describe("Title of the discussion topic"),
|
|
940
|
-
message: _zod.z.string().optional().describe("Body text of the discussion (supports HTML)"),
|
|
941
|
-
discussion_type: _zod.z.enum(["side_comment", "threaded"]).optional().describe("Discussion type: side_comment (flat) or threaded"),
|
|
942
|
-
published: _zod.z.boolean().optional().describe("Whether the topic is published"),
|
|
943
|
-
require_initial_post: _zod.z.boolean().optional().describe("Require students to post before seeing replies")
|
|
941
|
+
file_id: _zod.z.number().describe("The Canvas file ID")
|
|
944
942
|
},
|
|
945
943
|
annotations: {
|
|
946
944
|
destructiveHint: true,
|
|
947
945
|
openWorldHint: true
|
|
948
946
|
},
|
|
949
947
|
handler: async (params) => {
|
|
950
|
-
const
|
|
951
|
-
return canvas.
|
|
952
|
-
title: params.title,
|
|
953
|
-
message: params.message,
|
|
954
|
-
discussion_type: params.discussion_type,
|
|
955
|
-
published: params.published,
|
|
956
|
-
require_initial_post: params.require_initial_post
|
|
957
|
-
});
|
|
948
|
+
const file_id = params.file_id;
|
|
949
|
+
return canvas.files.delete(file_id);
|
|
958
950
|
}
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
951
|
+
}
|
|
952
|
+
];
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// src/tools/groups.ts
|
|
956
|
+
|
|
957
|
+
function groupTools(canvas) {
|
|
958
|
+
return [
|
|
959
|
+
{
|
|
960
|
+
name: "list_groups",
|
|
961
|
+
description: "List all groups in a course.",
|
|
962
|
+
inputSchema: {
|
|
963
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
970
964
|
},
|
|
971
965
|
annotations: {
|
|
972
|
-
|
|
966
|
+
readOnlyHint: true,
|
|
973
967
|
openWorldHint: true
|
|
974
968
|
},
|
|
975
969
|
handler: async (params) => {
|
|
976
970
|
const course_id = params.course_id;
|
|
977
|
-
|
|
978
|
-
const updateParams = {
|
|
979
|
-
title: params.title,
|
|
980
|
-
message: params.message,
|
|
981
|
-
published: params.published,
|
|
982
|
-
require_initial_post: params.require_initial_post
|
|
983
|
-
};
|
|
984
|
-
if (Object.values(updateParams).every((v) => v === void 0)) {
|
|
985
|
-
throw new Error("At least one field must be provided to update a discussion topic");
|
|
986
|
-
}
|
|
987
|
-
return canvas.discussions.update(course_id, topic_id, updateParams);
|
|
971
|
+
return canvas.groups.list(course_id);
|
|
988
972
|
}
|
|
989
973
|
},
|
|
990
974
|
{
|
|
991
|
-
name: "
|
|
992
|
-
description: "
|
|
975
|
+
name: "list_group_members",
|
|
976
|
+
description: "List all members of a group.",
|
|
993
977
|
inputSchema: {
|
|
994
|
-
|
|
995
|
-
topic_id: _zod.z.number().describe("The Canvas discussion topic ID to delete")
|
|
978
|
+
group_id: _zod.z.number().describe("The Canvas group ID")
|
|
996
979
|
},
|
|
997
980
|
annotations: {
|
|
998
|
-
|
|
981
|
+
readOnlyHint: true,
|
|
999
982
|
openWorldHint: true
|
|
1000
983
|
},
|
|
1001
984
|
handler: async (params) => {
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
985
|
+
const group_id = params.group_id;
|
|
986
|
+
return canvas.groups.listMembers(group_id);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
];
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// src/tools/health.ts
|
|
993
|
+
function healthTools(canvas) {
|
|
994
|
+
return [
|
|
995
|
+
{
|
|
996
|
+
name: "health_check",
|
|
997
|
+
description: "Check if the Canvas API is reachable and the token is valid. Returns ok/error status.",
|
|
998
|
+
inputSchema: {},
|
|
999
|
+
annotations: {
|
|
1000
|
+
readOnlyHint: true,
|
|
1001
|
+
openWorldHint: true
|
|
1002
|
+
},
|
|
1003
|
+
handler: async () => {
|
|
1004
|
+
await canvas.users.getProfile();
|
|
1005
|
+
return { status: "ok", message: "Canvas API is reachable" };
|
|
1006
1006
|
}
|
|
1007
1007
|
}
|
|
1008
1008
|
];
|
|
@@ -1151,246 +1151,330 @@ function moduleTools(canvas) {
|
|
|
1151
1151
|
];
|
|
1152
1152
|
}
|
|
1153
1153
|
|
|
1154
|
-
// src/tools/
|
|
1154
|
+
// src/tools/outcomes.ts
|
|
1155
1155
|
|
|
1156
|
-
function
|
|
1156
|
+
function outcomeTools(canvas) {
|
|
1157
1157
|
return [
|
|
1158
1158
|
{
|
|
1159
|
-
name: "
|
|
1160
|
-
description: "
|
|
1159
|
+
name: "get_root_outcome_group",
|
|
1160
|
+
description: "Get the root outcome group for an account or course context.",
|
|
1161
1161
|
inputSchema: {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
annotations: {
|
|
1165
|
-
readOnlyHint: true,
|
|
1166
|
-
openWorldHint: true
|
|
1162
|
+
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcomes from an account or course context."),
|
|
1163
|
+
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
|
|
1167
1164
|
},
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1165
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1166
|
+
handler: async (params) => canvas.outcomes.getRootOutcomeGroup(
|
|
1167
|
+
params.context_type,
|
|
1168
|
+
params.context_id
|
|
1169
|
+
)
|
|
1172
1170
|
},
|
|
1173
1171
|
{
|
|
1174
|
-
name: "
|
|
1175
|
-
description: "
|
|
1172
|
+
name: "list_outcome_groups",
|
|
1173
|
+
description: "List all outcome groups for an account or course context.",
|
|
1176
1174
|
inputSchema: {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
},
|
|
1180
|
-
annotations: {
|
|
1181
|
-
readOnlyHint: true,
|
|
1182
|
-
openWorldHint: true
|
|
1175
|
+
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome groups from an account or course context."),
|
|
1176
|
+
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
|
|
1183
1177
|
},
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1178
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1179
|
+
handler: async (params) => canvas.outcomes.listOutcomeGroups(
|
|
1180
|
+
params.context_type,
|
|
1181
|
+
params.context_id
|
|
1182
|
+
)
|
|
1189
1183
|
},
|
|
1190
1184
|
{
|
|
1191
|
-
name: "
|
|
1192
|
-
description: "
|
|
1185
|
+
name: "list_outcome_group_links",
|
|
1186
|
+
description: "List all outcome links in an account or course context.",
|
|
1193
1187
|
inputSchema: {
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
annotations: {
|
|
1201
|
-
destructiveHint: true,
|
|
1202
|
-
openWorldHint: true
|
|
1188
|
+
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome links from an account or course context."),
|
|
1189
|
+
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1190
|
+
outcome_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.'),
|
|
1191
|
+
outcome_group_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe(
|
|
1192
|
+
'Outcome group detail level. Use "full" to include expanded outcome group fields.'
|
|
1193
|
+
)
|
|
1203
1194
|
},
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1195
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1196
|
+
handler: async (params) => canvas.outcomes.listOutcomeGroupLinks(
|
|
1197
|
+
params.context_type,
|
|
1198
|
+
params.context_id,
|
|
1199
|
+
{
|
|
1200
|
+
outcome_style: params.outcome_style,
|
|
1201
|
+
outcome_group_style: params.outcome_group_style
|
|
1202
|
+
}
|
|
1203
|
+
)
|
|
1213
1204
|
},
|
|
1214
1205
|
{
|
|
1215
|
-
name: "
|
|
1216
|
-
description: "
|
|
1206
|
+
name: "get_outcome_group",
|
|
1207
|
+
description: "Get details for a specific outcome group in an account or course context.",
|
|
1217
1208
|
inputSchema: {
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
body: _zod.z.string().optional().describe("New HTML body content"),
|
|
1222
|
-
published: _zod.z.boolean().optional().describe("Whether the page is published"),
|
|
1223
|
-
editing_roles: _zod.z.string().optional().describe('Who can edit: "teachers", "students", "members", or "public"')
|
|
1224
|
-
},
|
|
1225
|
-
annotations: {
|
|
1226
|
-
destructiveHint: true,
|
|
1227
|
-
openWorldHint: true
|
|
1209
|
+
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
|
|
1210
|
+
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1211
|
+
outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
|
|
1228
1212
|
},
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
published: params.published,
|
|
1236
|
-
editing_roles: params.editing_roles
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1213
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1214
|
+
handler: async (params) => canvas.outcomes.getOutcomeGroup(
|
|
1215
|
+
params.context_type,
|
|
1216
|
+
params.context_id,
|
|
1217
|
+
params.outcome_group_id
|
|
1218
|
+
)
|
|
1239
1219
|
},
|
|
1240
1220
|
{
|
|
1241
|
-
name: "
|
|
1242
|
-
description: "
|
|
1221
|
+
name: "list_outcome_group_outcomes",
|
|
1222
|
+
description: "List the linked outcomes directly under a specific outcome group.",
|
|
1243
1223
|
inputSchema: {
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
destructiveHint: true,
|
|
1249
|
-
openWorldHint: true
|
|
1224
|
+
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
|
|
1225
|
+
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1226
|
+
outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID."),
|
|
1227
|
+
outcome_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.')
|
|
1250
1228
|
},
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
// src/tools/calendar.ts
|
|
1262
|
-
|
|
1263
|
-
function calendarTools(canvas) {
|
|
1264
|
-
return [
|
|
1229
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1230
|
+
handler: async (params) => canvas.outcomes.listGroupOutcomes(
|
|
1231
|
+
params.context_type,
|
|
1232
|
+
params.context_id,
|
|
1233
|
+
params.outcome_group_id,
|
|
1234
|
+
{
|
|
1235
|
+
outcome_style: params.outcome_style
|
|
1236
|
+
}
|
|
1237
|
+
)
|
|
1238
|
+
},
|
|
1265
1239
|
{
|
|
1266
|
-
name: "
|
|
1267
|
-
description: "List
|
|
1240
|
+
name: "list_outcome_group_subgroups",
|
|
1241
|
+
description: "List the immediate child outcome groups under a specific outcome group.",
|
|
1268
1242
|
inputSchema: {
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
readOnlyHint: true,
|
|
1273
|
-
openWorldHint: true
|
|
1243
|
+
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
|
|
1244
|
+
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1245
|
+
outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
|
|
1274
1246
|
},
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1247
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1248
|
+
handler: async (params) => canvas.outcomes.listGroupSubgroups(
|
|
1249
|
+
params.context_type,
|
|
1250
|
+
params.context_id,
|
|
1251
|
+
params.outcome_group_id
|
|
1252
|
+
)
|
|
1279
1253
|
},
|
|
1280
1254
|
{
|
|
1281
|
-
name: "
|
|
1282
|
-
description: "
|
|
1255
|
+
name: "get_outcome",
|
|
1256
|
+
description: "Get the full details for a specific learning outcome by ID.",
|
|
1283
1257
|
inputSchema: {
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
start_at: _zod.z.string().describe('Start time in ISO 8601 format, e.g. "2026-05-01T10:00:00Z"'),
|
|
1287
|
-
end_at: _zod.z.string().optional().describe("End time in ISO 8601 format. Omit for all-day events."),
|
|
1288
|
-
description: _zod.z.string().optional().describe("Event description (HTML allowed)"),
|
|
1289
|
-
location_name: _zod.z.string().optional().describe("Location name")
|
|
1258
|
+
outcome_id: _zod.z.number().describe("The Canvas outcome ID."),
|
|
1259
|
+
add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
|
|
1290
1260
|
},
|
|
1291
|
-
annotations: {
|
|
1292
|
-
|
|
1293
|
-
|
|
1261
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1262
|
+
handler: async (params) => canvas.outcomes.getOutcome(params.outcome_id, {
|
|
1263
|
+
add_defaults: params.add_defaults
|
|
1264
|
+
})
|
|
1265
|
+
},
|
|
1266
|
+
{
|
|
1267
|
+
name: "get_outcome_alignments",
|
|
1268
|
+
description: "Get outcome alignments for a course, optionally filtered to a specific student or assignment.",
|
|
1269
|
+
inputSchema: {
|
|
1270
|
+
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1271
|
+
student_id: _zod.z.number().optional().describe("Optional Canvas user ID of the student to filter alignments by."),
|
|
1272
|
+
assignment_id: _zod.z.number().optional().describe("Optional Canvas assignment ID to filter alignments by.")
|
|
1294
1273
|
},
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
end_at: params.end_at,
|
|
1301
|
-
description: params.description,
|
|
1302
|
-
location_name: params.location_name
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1274
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1275
|
+
handler: async (params) => canvas.outcomes.getOutcomeAlignments(params.course_id, {
|
|
1276
|
+
student_id: params.student_id,
|
|
1277
|
+
assignment_id: params.assignment_id
|
|
1278
|
+
})
|
|
1305
1279
|
},
|
|
1306
1280
|
{
|
|
1307
|
-
name: "
|
|
1308
|
-
description: "
|
|
1281
|
+
name: "get_outcome_results",
|
|
1282
|
+
description: "Get per-student outcome results for a course, with optional outcome, student, and alignment filters.",
|
|
1309
1283
|
inputSchema: {
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
location_name: _zod.z.string().optional().describe("New location name")
|
|
1284
|
+
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1285
|
+
user_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas user IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1286
|
+
outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the results."),
|
|
1287
|
+
include_alignments: _zod.z.boolean().optional().describe("Include linked alignment details in the response."),
|
|
1288
|
+
include_hidden: _zod.z.boolean().optional().describe("Include hidden outcomes when Canvas supports it.")
|
|
1316
1289
|
},
|
|
1317
|
-
annotations: {
|
|
1318
|
-
|
|
1319
|
-
|
|
1290
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1291
|
+
handler: async (params) => canvas.outcomes.getOutcomeResults(params.course_id, {
|
|
1292
|
+
user_ids: params.user_ids,
|
|
1293
|
+
outcome_ids: params.outcome_ids,
|
|
1294
|
+
include_alignments: params.include_alignments,
|
|
1295
|
+
include_hidden: params.include_hidden
|
|
1296
|
+
})
|
|
1297
|
+
},
|
|
1298
|
+
{
|
|
1299
|
+
name: "get_outcome_rollups",
|
|
1300
|
+
description: "Get outcome rollups for a course, optionally aggregated or filtered by students, outcomes, and sort options.",
|
|
1301
|
+
inputSchema: {
|
|
1302
|
+
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1303
|
+
aggregate: _zod.z.enum(["course"]).optional().describe("Aggregate all student rollups into a single course-level rollup."),
|
|
1304
|
+
aggregate_stat: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_ROLLUP_AGGREGATE_STATS).optional().describe('Statistic to use when aggregate="course".'),
|
|
1305
|
+
user_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas user IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1306
|
+
outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the rollups."),
|
|
1307
|
+
include_courses: _zod.z.boolean().optional().describe("Include linked course details in the response payload."),
|
|
1308
|
+
exclude: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional rollup exclusions for missing users or missing outcome results."),
|
|
1309
|
+
sort_by: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_ROLLUP_SORT_BY).optional().describe("Sort rollups by student name or by a specific outcome score."),
|
|
1310
|
+
sort_outcome_id: _zod.z.number().optional().describe('Outcome ID to sort by when sort_by="outcome".'),
|
|
1311
|
+
sort_order: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_SORT_ORDER).optional().describe("Sort order to apply when sorting rollups."),
|
|
1312
|
+
add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
|
|
1320
1313
|
},
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1314
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1315
|
+
handler: async (params) => canvas.outcomes.getOutcomeRollups(params.course_id, {
|
|
1316
|
+
aggregate: params.aggregate,
|
|
1317
|
+
aggregate_stat: params.aggregate_stat,
|
|
1318
|
+
user_ids: params.user_ids,
|
|
1319
|
+
outcome_ids: params.outcome_ids,
|
|
1320
|
+
include_courses: params.include_courses,
|
|
1321
|
+
exclude: params.exclude,
|
|
1322
|
+
sort_by: params.sort_by,
|
|
1323
|
+
sort_outcome_id: params.sort_outcome_id,
|
|
1324
|
+
sort_order: params.sort_order,
|
|
1325
|
+
add_defaults: params.add_defaults
|
|
1326
|
+
})
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
name: "get_outcome_contributing_scores",
|
|
1330
|
+
description: "Get assignment or quiz scores that contributed to a specific outcome for one or more students in a course.",
|
|
1331
|
+
inputSchema: {
|
|
1332
|
+
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1333
|
+
outcome_id: _zod.z.number().describe("The Canvas outcome ID."),
|
|
1334
|
+
user_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas user IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1335
|
+
only_assignment_alignments: _zod.z.boolean().optional().describe("Limit results to assignment alignments only."),
|
|
1336
|
+
show_unpublished_assignments: _zod.z.boolean().optional().describe("Include unpublished assignments in the contributing score results.")
|
|
1337
|
+
},
|
|
1338
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1339
|
+
handler: async (params) => canvas.outcomes.getOutcomeContributingScores(
|
|
1340
|
+
params.course_id,
|
|
1341
|
+
params.outcome_id,
|
|
1342
|
+
{
|
|
1343
|
+
user_ids: params.user_ids,
|
|
1344
|
+
only_assignment_alignments: params.only_assignment_alignments,
|
|
1345
|
+
show_unpublished_assignments: params.show_unpublished_assignments
|
|
1346
|
+
}
|
|
1347
|
+
)
|
|
1348
|
+
},
|
|
1349
|
+
{
|
|
1350
|
+
name: "get_outcome_mastery_distribution",
|
|
1351
|
+
description: "Get mastery distribution analytics for outcomes in a course, optionally filtered by students or outcomes.",
|
|
1352
|
+
inputSchema: {
|
|
1353
|
+
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1354
|
+
exclude: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional exclusions for missing users or missing outcome results."),
|
|
1355
|
+
outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the distribution results."),
|
|
1356
|
+
student_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas student IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1357
|
+
include_alignment_distributions: _zod.z.boolean().optional().describe("Include contributing score distributions for alignments."),
|
|
1358
|
+
only_assignment_alignments: _zod.z.boolean().optional().describe("When including alignment distributions, limit them to assignments only."),
|
|
1359
|
+
show_unpublished_assignments: _zod.z.boolean().optional().describe("Include unpublished assignments in alignment distributions."),
|
|
1360
|
+
add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
|
|
1361
|
+
},
|
|
1362
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1363
|
+
handler: async (params) => canvas.outcomes.getOutcomeMasteryDistribution(params.course_id, {
|
|
1364
|
+
exclude: params.exclude,
|
|
1365
|
+
outcome_ids: params.outcome_ids,
|
|
1366
|
+
student_ids: params.student_ids,
|
|
1367
|
+
include_alignment_distributions: params.include_alignment_distributions,
|
|
1368
|
+
only_assignment_alignments: params.only_assignment_alignments,
|
|
1369
|
+
show_unpublished_assignments: params.show_unpublished_assignments,
|
|
1370
|
+
add_defaults: params.add_defaults
|
|
1371
|
+
})
|
|
1331
1372
|
}
|
|
1332
1373
|
];
|
|
1333
1374
|
}
|
|
1334
1375
|
|
|
1335
|
-
// src/tools/
|
|
1376
|
+
// src/tools/pages.ts
|
|
1336
1377
|
|
|
1337
|
-
function
|
|
1378
|
+
function pageTools(canvas) {
|
|
1338
1379
|
return [
|
|
1339
1380
|
{
|
|
1340
|
-
name: "
|
|
1341
|
-
description: "List
|
|
1342
|
-
inputSchema: {
|
|
1381
|
+
name: "list_pages",
|
|
1382
|
+
description: "List all wiki pages in a course.",
|
|
1383
|
+
inputSchema: {
|
|
1384
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1385
|
+
},
|
|
1343
1386
|
annotations: {
|
|
1344
1387
|
readOnlyHint: true,
|
|
1345
1388
|
openWorldHint: true
|
|
1346
1389
|
},
|
|
1347
|
-
handler: async () => {
|
|
1348
|
-
|
|
1390
|
+
handler: async (params) => {
|
|
1391
|
+
const course_id = params.course_id;
|
|
1392
|
+
return canvas.pages.list(course_id);
|
|
1349
1393
|
}
|
|
1350
1394
|
},
|
|
1351
1395
|
{
|
|
1352
|
-
name: "
|
|
1353
|
-
description: "Get a single
|
|
1396
|
+
name: "get_page",
|
|
1397
|
+
description: "Get a single wiki page by its URL slug.",
|
|
1354
1398
|
inputSchema: {
|
|
1355
|
-
|
|
1399
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1400
|
+
page_url: _zod.z.string().describe('The page URL slug (e.g. "welcome-page")')
|
|
1356
1401
|
},
|
|
1357
1402
|
annotations: {
|
|
1358
1403
|
readOnlyHint: true,
|
|
1359
1404
|
openWorldHint: true
|
|
1360
1405
|
},
|
|
1361
1406
|
handler: async (params) => {
|
|
1362
|
-
|
|
1407
|
+
const course_id = params.course_id;
|
|
1408
|
+
const page_url = params.page_url;
|
|
1409
|
+
return canvas.pages.get(course_id, page_url);
|
|
1363
1410
|
}
|
|
1364
1411
|
},
|
|
1365
1412
|
{
|
|
1366
|
-
name: "
|
|
1367
|
-
description: "
|
|
1368
|
-
inputSchema: {
|
|
1413
|
+
name: "create_page",
|
|
1414
|
+
description: "Create a new wiki page in a course.",
|
|
1415
|
+
inputSchema: {
|
|
1416
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1417
|
+
title: _zod.z.string().describe("Title of the page"),
|
|
1418
|
+
body: _zod.z.string().optional().describe("HTML body content of the page"),
|
|
1419
|
+
published: _zod.z.boolean().optional().describe("Whether the page is published"),
|
|
1420
|
+
editing_roles: _zod.z.string().optional().describe('Who can edit: "teachers", "students", "members", or "public"')
|
|
1421
|
+
},
|
|
1369
1422
|
annotations: {
|
|
1370
|
-
|
|
1423
|
+
destructiveHint: true,
|
|
1371
1424
|
openWorldHint: true
|
|
1372
1425
|
},
|
|
1373
|
-
handler: async () => {
|
|
1374
|
-
|
|
1426
|
+
handler: async (params) => {
|
|
1427
|
+
const course_id = params.course_id;
|
|
1428
|
+
return canvas.pages.create(course_id, {
|
|
1429
|
+
title: params.title,
|
|
1430
|
+
body: params.body,
|
|
1431
|
+
published: params.published,
|
|
1432
|
+
editing_roles: params.editing_roles
|
|
1433
|
+
});
|
|
1375
1434
|
}
|
|
1376
1435
|
},
|
|
1377
1436
|
{
|
|
1378
|
-
name: "
|
|
1379
|
-
description: "
|
|
1437
|
+
name: "update_page",
|
|
1438
|
+
description: "Update an existing wiki page.",
|
|
1380
1439
|
inputSchema: {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1440
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1441
|
+
page_url: _zod.z.string().describe("The page URL slug"),
|
|
1442
|
+
title: _zod.z.string().optional().describe("New title for the page"),
|
|
1443
|
+
body: _zod.z.string().optional().describe("New HTML body content"),
|
|
1444
|
+
published: _zod.z.boolean().optional().describe("Whether the page is published"),
|
|
1445
|
+
editing_roles: _zod.z.string().optional().describe('Who can edit: "teachers", "students", "members", or "public"')
|
|
1384
1446
|
},
|
|
1385
1447
|
annotations: {
|
|
1386
1448
|
destructiveHint: true,
|
|
1387
1449
|
openWorldHint: true
|
|
1388
1450
|
},
|
|
1389
1451
|
handler: async (params) => {
|
|
1390
|
-
const
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1393
|
-
|
|
1452
|
+
const course_id = params.course_id;
|
|
1453
|
+
const page_url = params.page_url;
|
|
1454
|
+
return canvas.pages.update(course_id, page_url, {
|
|
1455
|
+
title: params.title,
|
|
1456
|
+
body: params.body,
|
|
1457
|
+
published: params.published,
|
|
1458
|
+
editing_roles: params.editing_roles
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
name: "delete_page",
|
|
1464
|
+
description: "Delete a wiki page from a course.",
|
|
1465
|
+
inputSchema: {
|
|
1466
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1467
|
+
page_url: _zod.z.string().describe("The page URL slug to delete")
|
|
1468
|
+
},
|
|
1469
|
+
annotations: {
|
|
1470
|
+
destructiveHint: true,
|
|
1471
|
+
openWorldHint: true
|
|
1472
|
+
},
|
|
1473
|
+
handler: async (params) => {
|
|
1474
|
+
const course_id = params.course_id;
|
|
1475
|
+
const page_url = params.page_url;
|
|
1476
|
+
await canvas.pages.delete(course_id, page_url);
|
|
1477
|
+
return { deleted: true, page_url };
|
|
1394
1478
|
}
|
|
1395
1479
|
}
|
|
1396
1480
|
];
|
|
@@ -1481,151 +1565,156 @@ function peerReviewTools(canvas) {
|
|
|
1481
1565
|
];
|
|
1482
1566
|
}
|
|
1483
1567
|
|
|
1484
|
-
// src/tools/
|
|
1568
|
+
// src/tools/quizzes.ts
|
|
1485
1569
|
|
|
1486
|
-
function
|
|
1570
|
+
function quizTools(canvas) {
|
|
1487
1571
|
return [
|
|
1488
1572
|
{
|
|
1489
|
-
name: "
|
|
1490
|
-
description: "
|
|
1573
|
+
name: "list_quizzes",
|
|
1574
|
+
description: "List all quizzes in a course.",
|
|
1491
1575
|
inputSchema: {
|
|
1492
|
-
|
|
1576
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1493
1577
|
},
|
|
1494
1578
|
annotations: {
|
|
1495
1579
|
readOnlyHint: true,
|
|
1496
1580
|
openWorldHint: true
|
|
1497
1581
|
},
|
|
1498
1582
|
handler: async (params) => {
|
|
1499
|
-
|
|
1583
|
+
const course_id = params.course_id;
|
|
1584
|
+
return canvas.quizzes.list(course_id);
|
|
1500
1585
|
}
|
|
1501
1586
|
},
|
|
1502
1587
|
{
|
|
1503
|
-
name: "
|
|
1504
|
-
description: "
|
|
1505
|
-
inputSchema: {
|
|
1588
|
+
name: "get_quiz",
|
|
1589
|
+
description: "Get details for a single quiz by ID.",
|
|
1590
|
+
inputSchema: {
|
|
1591
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1592
|
+
quiz_id: _zod.z.number().describe("The Canvas quiz ID")
|
|
1593
|
+
},
|
|
1506
1594
|
annotations: {
|
|
1507
1595
|
readOnlyHint: true,
|
|
1508
1596
|
openWorldHint: true
|
|
1509
1597
|
},
|
|
1510
|
-
handler: async () => {
|
|
1511
|
-
|
|
1598
|
+
handler: async (params) => {
|
|
1599
|
+
const course_id = params.course_id;
|
|
1600
|
+
const quiz_id = params.quiz_id;
|
|
1601
|
+
return canvas.quizzes.get(course_id, quiz_id);
|
|
1512
1602
|
}
|
|
1513
1603
|
},
|
|
1514
1604
|
{
|
|
1515
|
-
name: "
|
|
1516
|
-
description: "List
|
|
1605
|
+
name: "list_quiz_submissions",
|
|
1606
|
+
description: "List all submissions for a quiz.",
|
|
1517
1607
|
inputSchema: {
|
|
1518
|
-
|
|
1608
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1609
|
+
quiz_id: _zod.z.number().describe("The Canvas quiz ID")
|
|
1519
1610
|
},
|
|
1520
1611
|
annotations: {
|
|
1521
1612
|
readOnlyHint: true,
|
|
1522
1613
|
openWorldHint: true
|
|
1523
1614
|
},
|
|
1524
1615
|
handler: async (params) => {
|
|
1525
|
-
|
|
1616
|
+
const course_id = params.course_id;
|
|
1617
|
+
const quiz_id = params.quiz_id;
|
|
1618
|
+
return canvas.quizzes.listSubmissions(course_id, quiz_id);
|
|
1526
1619
|
}
|
|
1527
1620
|
},
|
|
1528
1621
|
{
|
|
1529
|
-
name: "
|
|
1530
|
-
description: "List
|
|
1622
|
+
name: "list_quiz_questions",
|
|
1623
|
+
description: "List all questions in a quiz.",
|
|
1531
1624
|
inputSchema: {
|
|
1532
|
-
|
|
1533
|
-
|
|
1625
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1626
|
+
quiz_id: _zod.z.number().describe("The Canvas quiz ID")
|
|
1534
1627
|
},
|
|
1535
1628
|
annotations: {
|
|
1536
1629
|
readOnlyHint: true,
|
|
1537
1630
|
openWorldHint: true
|
|
1538
1631
|
},
|
|
1539
1632
|
handler: async (params) => {
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1633
|
+
const course_id = params.course_id;
|
|
1634
|
+
const quiz_id = params.quiz_id;
|
|
1635
|
+
return canvas.quizzes.listQuestions(course_id, quiz_id);
|
|
1543
1636
|
}
|
|
1544
1637
|
},
|
|
1545
1638
|
{
|
|
1546
|
-
name: "
|
|
1547
|
-
description: "
|
|
1639
|
+
name: "get_quiz_submission_answers",
|
|
1640
|
+
description: "Get a student's answers for a quiz submission.",
|
|
1548
1641
|
inputSchema: {
|
|
1549
|
-
|
|
1550
|
-
search_term: _zod.z.string().optional().describe("Search users by name, email, or login")
|
|
1642
|
+
quiz_submission_id: _zod.z.number().describe("The Canvas quiz submission ID")
|
|
1551
1643
|
},
|
|
1552
1644
|
annotations: {
|
|
1553
1645
|
readOnlyHint: true,
|
|
1554
1646
|
openWorldHint: true
|
|
1555
1647
|
},
|
|
1556
1648
|
handler: async (params) => {
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
});
|
|
1649
|
+
const quiz_submission_id = params.quiz_submission_id;
|
|
1650
|
+
return canvas.quizzes.getSubmissionAnswers(quiz_submission_id);
|
|
1560
1651
|
}
|
|
1561
1652
|
},
|
|
1562
1653
|
{
|
|
1563
|
-
name: "
|
|
1564
|
-
description: "
|
|
1654
|
+
name: "score_quiz_question",
|
|
1655
|
+
description: "Score a specific question in a quiz submission. Specify attempt to score a particular attempt (omit for latest). Requires grading permissions.",
|
|
1565
1656
|
inputSchema: {
|
|
1566
|
-
|
|
1657
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1658
|
+
quiz_id: _zod.z.number().describe("The Canvas quiz ID"),
|
|
1659
|
+
submission_id: _zod.z.number().describe("The Canvas quiz submission ID"),
|
|
1660
|
+
question_id: _zod.z.number().describe("The Canvas quiz question ID"),
|
|
1661
|
+
score: _zod.z.number().describe("The score to assign"),
|
|
1662
|
+
comment: _zod.z.string().optional().describe("Optional feedback comment"),
|
|
1663
|
+
attempt: _zod.z.number().optional().describe("Quiz attempt number to score (omit for latest)")
|
|
1567
1664
|
},
|
|
1568
1665
|
annotations: {
|
|
1569
|
-
|
|
1666
|
+
destructiveHint: true,
|
|
1667
|
+
idempotentHint: true,
|
|
1570
1668
|
openWorldHint: true
|
|
1571
1669
|
},
|
|
1572
1670
|
handler: async (params) => {
|
|
1573
|
-
|
|
1671
|
+
const course_id = params.course_id;
|
|
1672
|
+
const quiz_id = params.quiz_id;
|
|
1673
|
+
const submission_id = params.submission_id;
|
|
1674
|
+
const question_id = params.question_id;
|
|
1675
|
+
const score = params.score;
|
|
1676
|
+
const comment = params.comment;
|
|
1677
|
+
const attempt = params.attempt;
|
|
1678
|
+
await canvas.quizzes.scoreQuestion(
|
|
1679
|
+
course_id,
|
|
1680
|
+
quiz_id,
|
|
1681
|
+
submission_id,
|
|
1682
|
+
question_id,
|
|
1683
|
+
score,
|
|
1684
|
+
comment,
|
|
1685
|
+
attempt
|
|
1686
|
+
);
|
|
1687
|
+
return { success: true };
|
|
1574
1688
|
}
|
|
1575
1689
|
}
|
|
1576
1690
|
];
|
|
1577
1691
|
}
|
|
1578
1692
|
|
|
1579
|
-
// src/tools/
|
|
1693
|
+
// src/tools/rubrics.ts
|
|
1580
1694
|
|
|
1581
|
-
function
|
|
1695
|
+
function rubricTools(canvas) {
|
|
1582
1696
|
return [
|
|
1583
1697
|
{
|
|
1584
|
-
name: "
|
|
1585
|
-
description: "
|
|
1698
|
+
name: "list_rubrics",
|
|
1699
|
+
description: "List all rubrics in a course.",
|
|
1586
1700
|
inputSchema: {
|
|
1587
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1588
|
-
search_term: _zod.z.string().describe("The keyword or phrase to search for"),
|
|
1589
|
-
content_types: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.SEARCH_CONTENT_TYPES)).optional().describe(
|
|
1590
|
-
"Content types to search. Defaults to all types: pages, discussions, assignments, announcements."
|
|
1591
|
-
)
|
|
1701
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1592
1702
|
},
|
|
1593
1703
|
annotations: {
|
|
1594
1704
|
readOnlyHint: true,
|
|
1595
1705
|
openWorldHint: true
|
|
1596
1706
|
},
|
|
1597
1707
|
handler: async (params) => {
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1600
|
-
const types = _nullishCoalesce(params.content_types, () => ( [
|
|
1601
|
-
..._chunkXAOI3FO6cjs.SEARCH_CONTENT_TYPES
|
|
1602
|
-
]));
|
|
1603
|
-
if (types.length === 0) return { results: [] };
|
|
1604
|
-
const settled = await Promise.allSettled(
|
|
1605
|
-
types.map((type) => canvas.analytics.searchContentType(courseId, searchTerm, type))
|
|
1606
|
-
);
|
|
1607
|
-
const fulfilled = settled.filter(
|
|
1608
|
-
(r) => r.status === "fulfilled"
|
|
1609
|
-
);
|
|
1610
|
-
if (fulfilled.length === 0) {
|
|
1611
|
-
const allErrors = settled.map(
|
|
1612
|
-
(result, index) => result.status === "rejected" ? `${types[index]}: ${formatError(result.reason)}` : null
|
|
1613
|
-
).filter((errorLine) => errorLine !== null);
|
|
1614
|
-
throw new Error(`All content type searches failed:
|
|
1615
|
-
${allErrors.join("\n")}`);
|
|
1616
|
-
}
|
|
1617
|
-
const results = fulfilled.flatMap((r) => r.value);
|
|
1618
|
-
const warnings = settled.map(
|
|
1619
|
-
(r, i) => r.status === "rejected" ? `${types[i]} search failed: ${formatError(r.reason)}` : null
|
|
1620
|
-
).filter((w) => w !== null);
|
|
1621
|
-
return warnings.length > 0 ? { results, warnings } : { results };
|
|
1708
|
+
const course_id = params.course_id;
|
|
1709
|
+
return canvas.rubrics.list(course_id);
|
|
1622
1710
|
}
|
|
1623
1711
|
},
|
|
1624
1712
|
{
|
|
1625
|
-
name: "
|
|
1626
|
-
description: "Get
|
|
1713
|
+
name: "get_rubric",
|
|
1714
|
+
description: "Get details for a single rubric by ID, including criteria.",
|
|
1627
1715
|
inputSchema: {
|
|
1628
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1716
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1717
|
+
rubric_id: _zod.z.number().describe("The Canvas rubric ID")
|
|
1629
1718
|
},
|
|
1630
1719
|
annotations: {
|
|
1631
1720
|
readOnlyHint: true,
|
|
@@ -1633,15 +1722,17 @@ ${allErrors.join("\n")}`);
|
|
|
1633
1722
|
},
|
|
1634
1723
|
handler: async (params) => {
|
|
1635
1724
|
const course_id = params.course_id;
|
|
1636
|
-
|
|
1725
|
+
const rubric_id = params.rubric_id;
|
|
1726
|
+
return canvas.rubrics.get(course_id, rubric_id);
|
|
1637
1727
|
}
|
|
1638
1728
|
},
|
|
1639
1729
|
{
|
|
1640
|
-
name: "
|
|
1641
|
-
description: "Get
|
|
1730
|
+
name: "get_rubric_assessment",
|
|
1731
|
+
description: "Get the rubric assessment for a specific student submission on an assignment.",
|
|
1642
1732
|
inputSchema: {
|
|
1643
1733
|
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1644
|
-
|
|
1734
|
+
assignment_id: _zod.z.number().describe("The Canvas assignment ID"),
|
|
1735
|
+
user_id: _zod.z.number().describe("The Canvas user ID")
|
|
1645
1736
|
},
|
|
1646
1737
|
annotations: {
|
|
1647
1738
|
readOnlyHint: true,
|
|
@@ -1649,23 +1740,35 @@ ${allErrors.join("\n")}`);
|
|
|
1649
1740
|
},
|
|
1650
1741
|
handler: async (params) => {
|
|
1651
1742
|
const course_id = params.course_id;
|
|
1652
|
-
const
|
|
1653
|
-
|
|
1743
|
+
const assignment_id = params.assignment_id;
|
|
1744
|
+
const user_id = params.user_id;
|
|
1745
|
+
return canvas.rubrics.getAssessment(course_id, assignment_id, user_id);
|
|
1654
1746
|
}
|
|
1655
1747
|
},
|
|
1656
1748
|
{
|
|
1657
|
-
name: "
|
|
1658
|
-
description: "
|
|
1749
|
+
name: "submit_rubric_assessment",
|
|
1750
|
+
description: "Submit a rubric assessment with scores and comments for each criterion.",
|
|
1659
1751
|
inputSchema: {
|
|
1660
|
-
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1752
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1753
|
+
association_id: _zod.z.number().describe("The rubric association ID"),
|
|
1754
|
+
data: _zod.z.array(
|
|
1755
|
+
_zod.z.object({
|
|
1756
|
+
criterion_id: _zod.z.string().describe("The rubric criterion ID"),
|
|
1757
|
+
points: _zod.z.number().describe("Points awarded for this criterion"),
|
|
1758
|
+
comments: _zod.z.string().describe("Feedback comment for this criterion")
|
|
1759
|
+
})
|
|
1760
|
+
).describe("Array of criterion assessments")
|
|
1661
1761
|
},
|
|
1662
1762
|
annotations: {
|
|
1663
|
-
|
|
1763
|
+
destructiveHint: true,
|
|
1764
|
+
idempotentHint: true,
|
|
1664
1765
|
openWorldHint: true
|
|
1665
1766
|
},
|
|
1666
1767
|
handler: async (params) => {
|
|
1667
1768
|
const course_id = params.course_id;
|
|
1668
|
-
|
|
1769
|
+
const association_id = params.association_id;
|
|
1770
|
+
const data = params.data;
|
|
1771
|
+
return canvas.rubrics.submitAssessment(course_id, association_id, data);
|
|
1669
1772
|
}
|
|
1670
1773
|
}
|
|
1671
1774
|
];
|
|
@@ -1732,307 +1835,293 @@ function studentTools(canvas) {
|
|
|
1732
1835
|
];
|
|
1733
1836
|
}
|
|
1734
1837
|
|
|
1735
|
-
// src/tools/
|
|
1736
|
-
|
|
1838
|
+
// src/tools/submissions.ts
|
|
1839
|
+
|
|
1840
|
+
function submissionTools(canvas) {
|
|
1737
1841
|
return [
|
|
1738
1842
|
{
|
|
1739
|
-
name: "
|
|
1740
|
-
description: "
|
|
1741
|
-
inputSchema: {
|
|
1843
|
+
name: "list_submissions",
|
|
1844
|
+
description: "List all submissions for an assignment in a course.",
|
|
1845
|
+
inputSchema: {
|
|
1846
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1847
|
+
assignment_id: _zod.z.number().describe("The Canvas assignment ID")
|
|
1848
|
+
},
|
|
1742
1849
|
annotations: {
|
|
1743
1850
|
readOnlyHint: true,
|
|
1744
1851
|
openWorldHint: true
|
|
1745
1852
|
},
|
|
1746
|
-
handler: async () => {
|
|
1747
|
-
|
|
1853
|
+
handler: async (params) => {
|
|
1854
|
+
const course_id = params.course_id;
|
|
1855
|
+
const assignment_id = params.assignment_id;
|
|
1856
|
+
return canvas.submissions.list(course_id, assignment_id);
|
|
1748
1857
|
}
|
|
1749
1858
|
},
|
|
1750
1859
|
{
|
|
1751
|
-
name: "
|
|
1752
|
-
description: "Get
|
|
1753
|
-
inputSchema: {
|
|
1860
|
+
name: "get_submission",
|
|
1861
|
+
description: "Get a single submission for a specific user on an assignment, including comments.",
|
|
1862
|
+
inputSchema: {
|
|
1863
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1864
|
+
assignment_id: _zod.z.number().describe("The Canvas assignment ID"),
|
|
1865
|
+
user_id: _zod.z.number().describe("The Canvas user ID")
|
|
1866
|
+
},
|
|
1754
1867
|
annotations: {
|
|
1755
1868
|
readOnlyHint: true,
|
|
1756
1869
|
openWorldHint: true
|
|
1757
1870
|
},
|
|
1758
|
-
handler: async () => {
|
|
1759
|
-
|
|
1871
|
+
handler: async (params) => {
|
|
1872
|
+
const course_id = params.course_id;
|
|
1873
|
+
const assignment_id = params.assignment_id;
|
|
1874
|
+
const user_id = params.user_id;
|
|
1875
|
+
return canvas.submissions.get(course_id, assignment_id, user_id);
|
|
1760
1876
|
}
|
|
1761
1877
|
},
|
|
1762
1878
|
{
|
|
1763
|
-
name: "
|
|
1764
|
-
description: "
|
|
1765
|
-
inputSchema: {
|
|
1879
|
+
name: "grade_submission",
|
|
1880
|
+
description: "Post or update a grade for a submission. Requires grading permissions.",
|
|
1881
|
+
inputSchema: {
|
|
1882
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1883
|
+
assignment_id: _zod.z.number().describe("The Canvas assignment ID"),
|
|
1884
|
+
user_id: _zod.z.number().describe("The Canvas user ID"),
|
|
1885
|
+
grade: _zod.z.string().describe('The grade to assign (e.g. "95", "A", "pass")')
|
|
1886
|
+
},
|
|
1766
1887
|
annotations: {
|
|
1767
|
-
|
|
1888
|
+
destructiveHint: true,
|
|
1889
|
+
idempotentHint: true,
|
|
1768
1890
|
openWorldHint: true
|
|
1769
1891
|
},
|
|
1770
|
-
handler: async () => {
|
|
1771
|
-
|
|
1892
|
+
handler: async (params) => {
|
|
1893
|
+
const course_id = params.course_id;
|
|
1894
|
+
const assignment_id = params.assignment_id;
|
|
1895
|
+
const user_id = params.user_id;
|
|
1896
|
+
const grade = params.grade;
|
|
1897
|
+
return canvas.submissions.grade(course_id, assignment_id, user_id, grade);
|
|
1772
1898
|
}
|
|
1773
1899
|
},
|
|
1774
1900
|
{
|
|
1775
|
-
name: "
|
|
1776
|
-
description: "
|
|
1777
|
-
inputSchema: {
|
|
1901
|
+
name: "comment_on_submission",
|
|
1902
|
+
description: "Add a text comment to a submission.",
|
|
1903
|
+
inputSchema: {
|
|
1904
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1905
|
+
assignment_id: _zod.z.number().describe("The Canvas assignment ID"),
|
|
1906
|
+
user_id: _zod.z.number().describe("The Canvas user ID"),
|
|
1907
|
+
comment: _zod.z.string().describe("The comment text to add")
|
|
1908
|
+
},
|
|
1778
1909
|
annotations: {
|
|
1779
|
-
|
|
1910
|
+
destructiveHint: true,
|
|
1780
1911
|
openWorldHint: true
|
|
1781
1912
|
},
|
|
1782
|
-
handler: async () => {
|
|
1783
|
-
|
|
1913
|
+
handler: async (params) => {
|
|
1914
|
+
const course_id = params.course_id;
|
|
1915
|
+
const assignment_id = params.assignment_id;
|
|
1916
|
+
const user_id = params.user_id;
|
|
1917
|
+
const comment = params.comment;
|
|
1918
|
+
return canvas.submissions.comment(course_id, assignment_id, user_id, comment);
|
|
1784
1919
|
}
|
|
1785
1920
|
}
|
|
1786
1921
|
];
|
|
1787
1922
|
}
|
|
1788
1923
|
|
|
1789
|
-
// src/tools/
|
|
1924
|
+
// src/tools/users.ts
|
|
1790
1925
|
|
|
1791
|
-
function
|
|
1926
|
+
function userTools(canvas) {
|
|
1792
1927
|
return [
|
|
1793
1928
|
{
|
|
1794
|
-
name: "
|
|
1795
|
-
description: "
|
|
1796
|
-
inputSchema: {
|
|
1797
|
-
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcomes from an account or course context."),
|
|
1798
|
-
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
|
|
1799
|
-
},
|
|
1800
|
-
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1801
|
-
handler: async (params) => canvas.outcomes.getRootOutcomeGroup(
|
|
1802
|
-
params.context_type,
|
|
1803
|
-
params.context_id
|
|
1804
|
-
)
|
|
1805
|
-
},
|
|
1806
|
-
{
|
|
1807
|
-
name: "list_outcome_groups",
|
|
1808
|
-
description: "List all outcome groups for an account or course context.",
|
|
1809
|
-
inputSchema: {
|
|
1810
|
-
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome groups from an account or course context."),
|
|
1811
|
-
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context.")
|
|
1812
|
-
},
|
|
1813
|
-
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1814
|
-
handler: async (params) => canvas.outcomes.listOutcomeGroups(
|
|
1815
|
-
params.context_type,
|
|
1816
|
-
params.context_id
|
|
1817
|
-
)
|
|
1818
|
-
},
|
|
1819
|
-
{
|
|
1820
|
-
name: "list_outcome_group_links",
|
|
1821
|
-
description: "List all outcome links in an account or course context.",
|
|
1822
|
-
inputSchema: {
|
|
1823
|
-
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("Whether to read outcome links from an account or course context."),
|
|
1824
|
-
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1825
|
-
outcome_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.'),
|
|
1826
|
-
outcome_group_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe(
|
|
1827
|
-
'Outcome group detail level. Use "full" to include expanded outcome group fields.'
|
|
1828
|
-
)
|
|
1829
|
-
},
|
|
1830
|
-
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
1831
|
-
handler: async (params) => canvas.outcomes.listOutcomeGroupLinks(
|
|
1832
|
-
params.context_type,
|
|
1833
|
-
params.context_id,
|
|
1834
|
-
{
|
|
1835
|
-
outcome_style: params.outcome_style,
|
|
1836
|
-
outcome_group_style: params.outcome_group_style
|
|
1837
|
-
}
|
|
1838
|
-
)
|
|
1839
|
-
},
|
|
1840
|
-
{
|
|
1841
|
-
name: "get_outcome_group",
|
|
1842
|
-
description: "Get details for a specific outcome group in an account or course context.",
|
|
1929
|
+
name: "list_students",
|
|
1930
|
+
description: "List all students enrolled in a course.",
|
|
1843
1931
|
inputSchema: {
|
|
1844
|
-
|
|
1845
|
-
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1846
|
-
outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
|
|
1932
|
+
course_id: _zod.z.number().describe("The Canvas course ID")
|
|
1847
1933
|
},
|
|
1848
|
-
annotations: {
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
params.context_id,
|
|
1852
|
-
params.outcome_group_id
|
|
1853
|
-
)
|
|
1854
|
-
},
|
|
1855
|
-
{
|
|
1856
|
-
name: "list_outcome_group_outcomes",
|
|
1857
|
-
description: "List the linked outcomes directly under a specific outcome group.",
|
|
1858
|
-
inputSchema: {
|
|
1859
|
-
context_type: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_CONTEXT_TYPES).describe("The outcome group context type."),
|
|
1860
|
-
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1861
|
-
outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID."),
|
|
1862
|
-
outcome_style: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_DETAIL_LEVELS).optional().describe('Outcome detail level. Use "full" to include expanded outcome fields.')
|
|
1934
|
+
annotations: {
|
|
1935
|
+
readOnlyHint: true,
|
|
1936
|
+
openWorldHint: true
|
|
1863
1937
|
},
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
params.outcome_group_id,
|
|
1869
|
-
{
|
|
1870
|
-
outcome_style: params.outcome_style
|
|
1871
|
-
}
|
|
1872
|
-
)
|
|
1938
|
+
handler: async (params) => {
|
|
1939
|
+
const course_id = params.course_id;
|
|
1940
|
+
return canvas.users.listStudents(course_id);
|
|
1941
|
+
}
|
|
1873
1942
|
},
|
|
1874
1943
|
{
|
|
1875
|
-
name: "
|
|
1876
|
-
description: "
|
|
1944
|
+
name: "get_user",
|
|
1945
|
+
description: "Get details for a single user by ID.",
|
|
1877
1946
|
inputSchema: {
|
|
1878
|
-
|
|
1879
|
-
context_id: _zod.z.number().describe("The Canvas account ID or course ID for the context."),
|
|
1880
|
-
outcome_group_id: _zod.z.number().describe("The Canvas outcome group ID.")
|
|
1947
|
+
user_id: _zod.z.number().describe("The Canvas user ID")
|
|
1881
1948
|
},
|
|
1882
|
-
annotations: {
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
params.context_id,
|
|
1886
|
-
params.outcome_group_id
|
|
1887
|
-
)
|
|
1888
|
-
},
|
|
1889
|
-
{
|
|
1890
|
-
name: "get_outcome",
|
|
1891
|
-
description: "Get the full details for a specific learning outcome by ID.",
|
|
1892
|
-
inputSchema: {
|
|
1893
|
-
outcome_id: _zod.z.number().describe("The Canvas outcome ID."),
|
|
1894
|
-
add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
|
|
1949
|
+
annotations: {
|
|
1950
|
+
readOnlyHint: true,
|
|
1951
|
+
openWorldHint: true
|
|
1895
1952
|
},
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
}
|
|
1953
|
+
handler: async (params) => {
|
|
1954
|
+
const user_id = params.user_id;
|
|
1955
|
+
return canvas.users.get(user_id);
|
|
1956
|
+
}
|
|
1900
1957
|
},
|
|
1901
1958
|
{
|
|
1902
|
-
name: "
|
|
1903
|
-
description: "Get
|
|
1904
|
-
inputSchema: {
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1959
|
+
name: "get_profile",
|
|
1960
|
+
description: "Get the profile of the currently authenticated user.",
|
|
1961
|
+
inputSchema: {},
|
|
1962
|
+
annotations: {
|
|
1963
|
+
readOnlyHint: true,
|
|
1964
|
+
openWorldHint: true
|
|
1908
1965
|
},
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
assignment_id: params.assignment_id
|
|
1913
|
-
})
|
|
1966
|
+
handler: async () => {
|
|
1967
|
+
return canvas.users.getProfile();
|
|
1968
|
+
}
|
|
1914
1969
|
},
|
|
1915
1970
|
{
|
|
1916
|
-
name: "
|
|
1917
|
-
description: "
|
|
1971
|
+
name: "search_users",
|
|
1972
|
+
description: "Search for users in a Canvas account by name, login, or email.",
|
|
1918
1973
|
inputSchema: {
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
include_hidden: _zod.z.boolean().optional().describe("Include hidden outcomes when Canvas supports it.")
|
|
1974
|
+
account_id: _zod.z.number().describe("The Canvas account ID"),
|
|
1975
|
+
search_term: _zod.z.string().describe("The search term (name, login, or email)"),
|
|
1976
|
+
sort: _zod.z.enum(["username", "email", "sis_id", "last_login"]).optional().describe("Sort field"),
|
|
1977
|
+
order: _zod.z.enum(["asc", "desc"]).optional().describe("Sort order")
|
|
1924
1978
|
},
|
|
1925
|
-
annotations: {
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
outcome_ids: params.outcome_ids,
|
|
1929
|
-
include_alignments: params.include_alignments,
|
|
1930
|
-
include_hidden: params.include_hidden
|
|
1931
|
-
})
|
|
1932
|
-
},
|
|
1933
|
-
{
|
|
1934
|
-
name: "get_outcome_rollups",
|
|
1935
|
-
description: "Get outcome rollups for a course, optionally aggregated or filtered by students, outcomes, and sort options.",
|
|
1936
|
-
inputSchema: {
|
|
1937
|
-
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1938
|
-
aggregate: _zod.z.enum(["course"]).optional().describe("Aggregate all student rollups into a single course-level rollup."),
|
|
1939
|
-
aggregate_stat: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_ROLLUP_AGGREGATE_STATS).optional().describe('Statistic to use when aggregate="course".'),
|
|
1940
|
-
user_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas user IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1941
|
-
outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the rollups."),
|
|
1942
|
-
include_courses: _zod.z.boolean().optional().describe("Include linked course details in the response payload."),
|
|
1943
|
-
exclude: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional rollup exclusions for missing users or missing outcome results."),
|
|
1944
|
-
sort_by: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_ROLLUP_SORT_BY).optional().describe("Sort rollups by student name or by a specific outcome score."),
|
|
1945
|
-
sort_outcome_id: _zod.z.number().optional().describe('Outcome ID to sort by when sort_by="outcome".'),
|
|
1946
|
-
sort_order: _zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_SORT_ORDER).optional().describe("Sort order to apply when sorting rollups."),
|
|
1947
|
-
add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
|
|
1979
|
+
annotations: {
|
|
1980
|
+
readOnlyHint: true,
|
|
1981
|
+
openWorldHint: true
|
|
1948
1982
|
},
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
sort_by: params.sort_by,
|
|
1958
|
-
sort_outcome_id: params.sort_outcome_id,
|
|
1959
|
-
sort_order: params.sort_order,
|
|
1960
|
-
add_defaults: params.add_defaults
|
|
1961
|
-
})
|
|
1983
|
+
handler: async (params) => {
|
|
1984
|
+
return canvas.users.searchUsers(
|
|
1985
|
+
params.account_id,
|
|
1986
|
+
params.search_term,
|
|
1987
|
+
params.sort,
|
|
1988
|
+
params.order
|
|
1989
|
+
);
|
|
1990
|
+
}
|
|
1962
1991
|
},
|
|
1963
1992
|
{
|
|
1964
|
-
name: "
|
|
1965
|
-
description: "
|
|
1993
|
+
name: "list_course_users",
|
|
1994
|
+
description: "List all users in a course, optionally filtered by enrollment type.",
|
|
1966
1995
|
inputSchema: {
|
|
1967
|
-
course_id: _zod.z.number().describe("The Canvas course ID
|
|
1968
|
-
|
|
1969
|
-
user_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas user IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1970
|
-
only_assignment_alignments: _zod.z.boolean().optional().describe("Limit results to assignment alignments only."),
|
|
1971
|
-
show_unpublished_assignments: _zod.z.boolean().optional().describe("Include unpublished assignments in the contributing score results.")
|
|
1996
|
+
course_id: _zod.z.number().describe("The Canvas course ID"),
|
|
1997
|
+
enrollment_type: _zod.z.enum(["student", "teacher", "ta", "observer", "designer"]).optional().describe("Filter by enrollment type")
|
|
1972
1998
|
},
|
|
1973
|
-
annotations: {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
params.outcome_id,
|
|
1977
|
-
{
|
|
1978
|
-
user_ids: params.user_ids,
|
|
1979
|
-
only_assignment_alignments: params.only_assignment_alignments,
|
|
1980
|
-
show_unpublished_assignments: params.show_unpublished_assignments
|
|
1981
|
-
}
|
|
1982
|
-
)
|
|
1983
|
-
},
|
|
1984
|
-
{
|
|
1985
|
-
name: "get_outcome_mastery_distribution",
|
|
1986
|
-
description: "Get mastery distribution analytics for outcomes in a course, optionally filtered by students or outcomes.",
|
|
1987
|
-
inputSchema: {
|
|
1988
|
-
course_id: _zod.z.number().describe("The Canvas course ID."),
|
|
1989
|
-
exclude: _zod.z.array(_zod.z.enum(_chunkXAOI3FO6cjs.OUTCOME_EXCLUDE_OPTIONS)).optional().describe("Optional exclusions for missing users or missing outcome results."),
|
|
1990
|
-
outcome_ids: _zod.z.array(_zod.z.number()).optional().describe("Optional outcome IDs to restrict the distribution results."),
|
|
1991
|
-
student_ids: _zod.z.array(_zod.z.union([_zod.z.number(), _zod.z.string()])).optional().describe('Optional Canvas student IDs or SIS user IDs prefixed with "sis_user_id:".'),
|
|
1992
|
-
include_alignment_distributions: _zod.z.boolean().optional().describe("Include contributing score distributions for alignments."),
|
|
1993
|
-
only_assignment_alignments: _zod.z.boolean().optional().describe("When including alignment distributions, limit them to assignments only."),
|
|
1994
|
-
show_unpublished_assignments: _zod.z.boolean().optional().describe("Include unpublished assignments in alignment distributions."),
|
|
1995
|
-
add_defaults: _zod.z.boolean().optional().describe("Include default mastery colors and levels when Canvas supports it.")
|
|
1999
|
+
annotations: {
|
|
2000
|
+
readOnlyHint: true,
|
|
2001
|
+
openWorldHint: true
|
|
1996
2002
|
},
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
only_assignment_alignments: params.only_assignment_alignments,
|
|
2004
|
-
show_unpublished_assignments: params.show_unpublished_assignments,
|
|
2005
|
-
add_defaults: params.add_defaults
|
|
2006
|
-
})
|
|
2003
|
+
handler: async (params) => {
|
|
2004
|
+
return canvas.users.listCourseUsers(
|
|
2005
|
+
params.course_id,
|
|
2006
|
+
params.enrollment_type
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2007
2009
|
}
|
|
2008
2010
|
];
|
|
2009
2011
|
}
|
|
2010
2012
|
|
|
2013
|
+
// src/tools/catalog.ts
|
|
2014
|
+
var toolDomainCatalog = [
|
|
2015
|
+
{
|
|
2016
|
+
domain: "health",
|
|
2017
|
+
defaultPrimaryAudience: "shared",
|
|
2018
|
+
getTools: healthTools
|
|
2019
|
+
},
|
|
2020
|
+
{
|
|
2021
|
+
domain: "courses",
|
|
2022
|
+
defaultPrimaryAudience: "shared",
|
|
2023
|
+
getTools: courseTools
|
|
2024
|
+
},
|
|
2025
|
+
{
|
|
2026
|
+
domain: "assignments",
|
|
2027
|
+
defaultPrimaryAudience: "educator",
|
|
2028
|
+
getTools: assignmentTools
|
|
2029
|
+
},
|
|
2030
|
+
{
|
|
2031
|
+
domain: "submissions",
|
|
2032
|
+
defaultPrimaryAudience: "educator",
|
|
2033
|
+
getTools: submissionTools
|
|
2034
|
+
},
|
|
2035
|
+
{
|
|
2036
|
+
domain: "rubrics",
|
|
2037
|
+
defaultPrimaryAudience: "educator",
|
|
2038
|
+
getTools: rubricTools
|
|
2039
|
+
},
|
|
2040
|
+
{
|
|
2041
|
+
domain: "quizzes",
|
|
2042
|
+
defaultPrimaryAudience: "educator",
|
|
2043
|
+
getTools: quizTools
|
|
2044
|
+
},
|
|
2045
|
+
{
|
|
2046
|
+
domain: "files",
|
|
2047
|
+
defaultPrimaryAudience: "shared",
|
|
2048
|
+
getTools: fileTools
|
|
2049
|
+
},
|
|
2050
|
+
{
|
|
2051
|
+
domain: "users",
|
|
2052
|
+
defaultPrimaryAudience: "educator",
|
|
2053
|
+
getTools: userTools
|
|
2054
|
+
},
|
|
2055
|
+
{
|
|
2056
|
+
domain: "groups",
|
|
2057
|
+
defaultPrimaryAudience: "shared",
|
|
2058
|
+
getTools: groupTools
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
domain: "enrollments",
|
|
2062
|
+
defaultPrimaryAudience: "admin",
|
|
2063
|
+
getTools: enrollmentTools
|
|
2064
|
+
},
|
|
2065
|
+
{
|
|
2066
|
+
domain: "discussions",
|
|
2067
|
+
defaultPrimaryAudience: "shared",
|
|
2068
|
+
getTools: discussionTools
|
|
2069
|
+
},
|
|
2070
|
+
{
|
|
2071
|
+
domain: "modules",
|
|
2072
|
+
defaultPrimaryAudience: "educator",
|
|
2073
|
+
getTools: moduleTools
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
domain: "pages",
|
|
2077
|
+
defaultPrimaryAudience: "educator",
|
|
2078
|
+
getTools: pageTools
|
|
2079
|
+
},
|
|
2080
|
+
{
|
|
2081
|
+
domain: "calendar",
|
|
2082
|
+
defaultPrimaryAudience: "shared",
|
|
2083
|
+
getTools: calendarTools
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
domain: "conversations",
|
|
2087
|
+
defaultPrimaryAudience: "shared",
|
|
2088
|
+
getTools: conversationTools
|
|
2089
|
+
},
|
|
2090
|
+
{
|
|
2091
|
+
domain: "peer_reviews",
|
|
2092
|
+
defaultPrimaryAudience: "shared",
|
|
2093
|
+
getTools: peerReviewTools
|
|
2094
|
+
},
|
|
2095
|
+
{
|
|
2096
|
+
domain: "accounts",
|
|
2097
|
+
defaultPrimaryAudience: "admin",
|
|
2098
|
+
getTools: accountTools
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
domain: "analytics",
|
|
2102
|
+
defaultPrimaryAudience: "educator",
|
|
2103
|
+
getTools: analyticsTools
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
domain: "outcomes",
|
|
2107
|
+
defaultPrimaryAudience: "educator",
|
|
2108
|
+
getTools: outcomeTools
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
domain: "student",
|
|
2112
|
+
defaultPrimaryAudience: "student",
|
|
2113
|
+
getTools: studentTools
|
|
2114
|
+
},
|
|
2115
|
+
{
|
|
2116
|
+
domain: "dashboard",
|
|
2117
|
+
defaultPrimaryAudience: "student",
|
|
2118
|
+
getTools: dashboardTools
|
|
2119
|
+
}
|
|
2120
|
+
];
|
|
2121
|
+
|
|
2011
2122
|
// src/tools/index.ts
|
|
2012
2123
|
function getAllTools(canvas) {
|
|
2013
|
-
return
|
|
2014
|
-
...healthTools(canvas),
|
|
2015
|
-
...courseTools(canvas),
|
|
2016
|
-
...assignmentTools(canvas),
|
|
2017
|
-
...submissionTools(canvas),
|
|
2018
|
-
...rubricTools(canvas),
|
|
2019
|
-
...quizTools(canvas),
|
|
2020
|
-
...fileTools(canvas),
|
|
2021
|
-
...userTools(canvas),
|
|
2022
|
-
...groupTools(canvas),
|
|
2023
|
-
...enrollmentTools(canvas),
|
|
2024
|
-
...discussionTools(canvas),
|
|
2025
|
-
...moduleTools(canvas),
|
|
2026
|
-
...pageTools(canvas),
|
|
2027
|
-
...calendarTools(canvas),
|
|
2028
|
-
...conversationTools(canvas),
|
|
2029
|
-
...peerReviewTools(canvas),
|
|
2030
|
-
...accountTools(canvas),
|
|
2031
|
-
...analyticsTools(canvas),
|
|
2032
|
-
...outcomeTools(canvas),
|
|
2033
|
-
...studentTools(canvas),
|
|
2034
|
-
...dashboardTools(canvas)
|
|
2035
|
-
];
|
|
2124
|
+
return toolDomainCatalog.flatMap((registration) => registration.getTools(canvas));
|
|
2036
2125
|
}
|
|
2037
2126
|
function registerAllTools(server, canvas) {
|
|
2038
2127
|
const tools = getAllTools(canvas);
|
|
@@ -2177,4 +2266,4 @@ function createCanvasMCPServer(config) {
|
|
|
2177
2266
|
|
|
2178
2267
|
|
|
2179
2268
|
exports.createCanvasMCPServer = createCanvasMCPServer;
|
|
2180
|
-
//# sourceMappingURL=chunk-
|
|
2269
|
+
//# sourceMappingURL=chunk-2BS2WOAF.cjs.map
|